bump to reddit v3 api (#209)

This commit is contained in:
Ben Senescu 2026-05-21 00:08:50 -04:00 committed by GitHub
parent 4f638db702
commit 3456af12fe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 35 additions and 33 deletions

View File

@ -131,7 +131,7 @@ function PostHogBootstrap() {
redditSignupInFlightRef.current = true; redditSignupInFlightRef.current = true;
void captureRedditConversionEvent({ void captureRedditConversionEvent({
data: { attribution, eventType: "SignUp" }, data: { attribution, eventType: "SIGN_UP" },
}) })
.then((result) => { .then((result) => {
if (result.status === "sent" || result.status === "already_sent") { if (result.status === "sent" || result.status === "already_sent") {

View File

@ -81,7 +81,7 @@ function BillingPageContent() {
if (!attribution) return; if (!attribution) return;
void captureRedditConversionEvent({ void captureRedditConversionEvent({
data: { attribution, eventType: "Purchase" }, data: { attribution, eventType: "PURCHASE" },
}); });
}, [billingRouteState, checkoutCompleted]); }, [billingRouteState, checkoutCompleted]);

View File

@ -59,7 +59,7 @@ function SubscribePageContent() {
const attribution = getStoredRedditAttribution(); const attribution = getStoredRedditAttribution();
if (attribution) { if (attribution) {
void captureRedditConversionEvent({ void captureRedditConversionEvent({
data: { attribution, eventType: "Purchase" }, data: { attribution, eventType: "PURCHASE" },
}).finally(() => { }).finally(() => {
void navigate({ to: "/", replace: true }); void navigate({ to: "/", replace: true });
}); });

View File

@ -7,7 +7,7 @@ import {
type RedditAttributionInput, type RedditAttributionInput,
} from "@/shared/reddit-attribution"; } from "@/shared/reddit-attribution";
type RedditConversionType = "SignUp" | "Purchase"; type RedditConversionType = "SIGN_UP" | "PURCHASE";
type CaptureRedditConversionArgs = { type CaptureRedditConversionArgs = {
attribution: RedditAttributionInput; attribution: RedditAttributionInput;
@ -34,12 +34,12 @@ async function sha256(value: string) {
} }
function getRedditConfig() { function getRedditConfig() {
const accountId = getEnv("REDDIT_AD_ACCOUNT_ID") || getEnv("REDDIT_PIXEL_ID"); const pixelId = getEnv("REDDIT_PIXEL_ID");
const accessToken = getEnv("REDDIT_CONVERSIONS_ACCESS_TOKEN"); const accessToken = getEnv("REDDIT_CONVERSIONS_ACCESS_TOKEN");
if (!accountId || !accessToken) return null; if (!pixelId || !accessToken) return null;
return { accountId, accessToken }; return { accessToken, pixelId };
} }
async function upsertAttribution(args: CaptureRedditConversionArgs) { async function upsertAttribution(args: CaptureRedditConversionArgs) {
@ -88,7 +88,7 @@ async function hasSentConversion(args: CaptureRedditConversionArgs) {
const existing = await db.query.redditAttributions.findFirst({ const existing = await db.query.redditAttributions.findFirst({
where: eq(redditAttributions.userId, args.userId), where: eq(redditAttributions.userId, args.userId),
}); });
return args.eventType === "SignUp" return args.eventType === "SIGN_UP"
? Boolean(existing?.signupSentAt) ? Boolean(existing?.signupSentAt)
: Boolean(existing?.purchaseSentAt); : Boolean(existing?.purchaseSentAt);
} }
@ -96,7 +96,7 @@ async function hasSentConversion(args: CaptureRedditConversionArgs) {
async function markConversionSent(args: CaptureRedditConversionArgs) { async function markConversionSent(args: CaptureRedditConversionArgs) {
const now = new Date().toISOString(); const now = new Date().toISOString();
const sentColumn = const sentColumn =
args.eventType === "SignUp" ? "signupSentAt" : "purchaseSentAt"; args.eventType === "SIGN_UP" ? "signupSentAt" : "purchaseSentAt";
await db await db
.update(redditAttributions) .update(redditAttributions)
@ -118,25 +118,26 @@ export async function captureRedditConversion(
const config = getRedditConfig(); const config = getRedditConfig();
if (!config) return "stored" as const; if (!config) return "stored" as const;
const eventMetadata: Record<string, unknown> = { const metadata: Record<string, unknown> = {
conversion_id: args.conversionId, conversion_id: args.conversionId,
transaction_id: args.conversionId,
}; };
if (args.valueDecimal !== undefined) { if (args.valueDecimal !== undefined) {
eventMetadata.value_decimal = args.valueDecimal; metadata.currency = args.currency ?? "USD";
eventMetadata.currency = args.currency ?? "USD"; metadata.item_count = 1;
eventMetadata.item_count = 1; metadata.value = args.valueDecimal;
} }
const payload = { const payload = {
data: {
events: [ events: [
{ {
action_source: "WEBSITE",
click_id: args.attribution.clickId, click_id: args.attribution.clickId,
event_at: new Date().toISOString(), event_at: Date.now(),
event_type: { metadata,
type: {
tracking_type: args.eventType, tracking_type: args.eventType,
}, },
event_metadata: eventMetadata,
user: { user: {
email: await sha256(args.email), email: await sha256(args.email),
external_id: await sha256(args.userId), external_id: await sha256(args.userId),
@ -144,10 +145,11 @@ export async function captureRedditConversion(
}, },
}, },
], ],
},
}; };
const response = await fetch( const response = await fetch(
`https://ads-api.reddit.com/api/v2.0/conversions/events/${config.accountId}`, `https://ads-api.reddit.com/api/v3/pixels/${config.pixelId}/conversion_events`,
{ {
method: "POST", method: "POST",
headers: { headers: {

View File

@ -6,7 +6,7 @@ import { requireAuthenticatedContext } from "@/serverFunctions/middleware";
const conversionInputSchema = z.object({ const conversionInputSchema = z.object({
attribution: redditAttributionSchema, attribution: redditAttributionSchema,
eventType: z.enum(["SignUp", "Purchase"]), eventType: z.enum(["SIGN_UP", "PURCHASE"]),
}); });
export const captureRedditConversionEvent = createServerFn({ method: "POST" }) export const captureRedditConversionEvent = createServerFn({ method: "POST" })
@ -15,13 +15,13 @@ export const captureRedditConversionEvent = createServerFn({ method: "POST" })
.handler(async ({ data, context }) => { .handler(async ({ data, context }) => {
const status = await captureRedditConversion({ const status = await captureRedditConversion({
attribution: data.attribution, attribution: data.attribution,
conversionId: `${data.eventType.toLowerCase()}:${context.userId}`, conversionId: `${data.eventType === "SIGN_UP" ? "signup" : "purchase"}:${context.userId}`,
email: context.userEmail, email: context.userEmail,
eventType: data.eventType, eventType: data.eventType,
organizationId: context.organizationId, organizationId: context.organizationId,
userId: context.userId, userId: context.userId,
valueDecimal: data.eventType === "Purchase" ? 10 : undefined, valueDecimal: data.eventType === "PURCHASE" ? 10 : undefined,
currency: data.eventType === "Purchase" ? "USD" : undefined, currency: data.eventType === "PURCHASE" ? "USD" : undefined,
}); });
return { status }; return { status };