Files
manoon-headless/src/app/api/email-capture/route.ts
T
Unchained eb711fbf1a
Build and Deploy / build (push) Has been cancelled
feat(popup): add email capture popup with Mautic integration
- Email capture popup with scroll (10%) and exit intent triggers
- First name field and full tracking (UTM, device, time on page)
- Mautic API integration for contact creation
- GeoIP detection for country/region
- 4 locale support (sr, en, de, fr)
- Mautic tracking script in layout
2026-04-03 20:44:15 +02:00

102 lines
2.6 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { createMauticContact } from "@/lib/mautic";
const requestCache = new Map<string, number>();
const DEBOUNCE_MS = 5000;
export async function POST(request: NextRequest) {
try {
const body = await request.json();
const {
email,
locale,
country,
countryCode,
source,
trigger,
firstName,
lastName,
timeOnPage,
referrer,
pageUrl,
pageLanguage,
preferredLocale,
deviceName,
deviceOS,
userAgent,
utmSource,
utmMedium,
utmCampaign,
utmContent,
fbclid,
} = body;
if (!email || !email.includes("@")) {
return NextResponse.json(
{ error: "Invalid email" },
{ status: 400 }
);
}
const cacheKey = `${email}:${Date.now()}`;
const lastRequest = requestCache.get(cacheKey);
if (lastRequest && Date.now() - lastRequest < DEBOUNCE_MS) {
return NextResponse.json(
{ error: "Please wait before submitting again" },
{ status: 429 }
);
}
requestCache.set(cacheKey, Date.now());
const tags = [
"source:popup",
`locale:${locale || "en"}`,
`country:${countryCode || "XX"}`,
`popup_${trigger || "unknown"}`,
"lead:warm",
...(utmSource ? [`utm:${utmSource}`] : []),
...(deviceName ? [`device:${deviceName}`] : []),
];
const forwardedFor = request.headers.get("x-forwarded-for");
const realIP = request.headers.get("x-real-ip");
const ipAddress = forwardedFor?.split(",")[0]?.trim() || realIP || "unknown";
const result = await createMauticContact(email, tags, {
firstName: firstName || "",
lastName: lastName || "",
country: country || "",
preferredLocale: preferredLocale || locale || "en",
ipAddress,
utmSource: utmSource || "",
utmMedium: utmMedium || "",
utmCampaign: utmCampaign || "",
utmContent: utmContent || "",
pageUrl: pageUrl || request.headers.get("referer") || "",
});
console.log("Email capture success:", {
email,
firstName,
timeOnPage,
deviceName,
deviceOS,
utmSource,
utmMedium,
result
});
return NextResponse.json({
success: true,
alreadySubscribed: result.alreadyExists,
contactId: result.contactId,
});
} catch (error) {
console.error("Email capture error:", error);
return NextResponse.json(
{ error: "Failed to process subscription", details: error instanceof Error ? error.message : "Unknown error" },
{ status: 500 }
);
}
}