mirror of
https://github.com/neynarxyz/create-farcaster-mini-app.git
synced 2025-11-16 08:08:56 -05:00
feat: add optional amplitude tracking
This commit is contained in:
parent
3fcd2f6e52
commit
7df556740d
15
bin/init.js
15
bin/init.js
@ -76,7 +76,7 @@ export async function init() {
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'useNeynar',
|
||||
message: '🪐 Neynar is an API that makes it easy to build on Farcaster.\n\n' +
|
||||
message: `🪐 ${purple}${bright}${italic}Neynar is an API that makes it easy to build on Farcaster.${reset}\n\n` +
|
||||
'Benefits of using Neynar in your mini app:\n' +
|
||||
'- Pre-configured webhook handling (no setup required)\n' +
|
||||
'- Automatic mini app analytics in your dev portal\n' +
|
||||
@ -252,6 +252,17 @@ export async function init() {
|
||||
]);
|
||||
answers.useTunnel = hostingAnswer.useTunnel;
|
||||
|
||||
// Ask about analytics opt-out
|
||||
const analyticsAnswer = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'enableAnalytics',
|
||||
message: 'Would you like to help improve Neynar products by sharing usage data from your mini app?',
|
||||
default: true
|
||||
}
|
||||
]);
|
||||
answers.enableAnalytics = analyticsAnswer.enableAnalytics;
|
||||
|
||||
const projectName = answers.projectName;
|
||||
const projectDirName = projectName.replace(/\s+/g, '-').toLowerCase();
|
||||
const projectPath = path.join(process.cwd(), projectDirName);
|
||||
@ -374,6 +385,8 @@ export async function init() {
|
||||
fs.appendFileSync(envPath, `\nNEXT_PUBLIC_FRAME_PRIMARY_CATEGORY="${answers.primaryCategory}"`);
|
||||
fs.appendFileSync(envPath, `\nNEXT_PUBLIC_FRAME_TAGS="${answers.tags.join(',')}"`);
|
||||
fs.appendFileSync(envPath, `\nNEXT_PUBLIC_FRAME_BUTTON_TEXT="${answers.buttonText}"`);
|
||||
fs.appendFileSync(envPath, `\nNEXT_PUBLIC_ANALYTICS_ENABLED="${answers.enableAnalytics}"`);
|
||||
|
||||
fs.appendFileSync(envPath, `\nNEXTAUTH_SECRET="${crypto.randomBytes(32).toString('hex')}"`);
|
||||
if (useNeynar && neynarApiKey && neynarClientId) {
|
||||
fs.appendFileSync(envPath, `\nNEYNAR_API_KEY="${neynarApiKey}"`);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@neynar/create-farcaster-mini-app",
|
||||
"version": "1.2.28",
|
||||
"version": "1.2.29",
|
||||
"type": "module",
|
||||
"private": false,
|
||||
"access": "public",
|
||||
|
||||
@ -355,6 +355,9 @@ async function main() {
|
||||
`NEXT_PUBLIC_FRAME_TAGS="${process.env.NEXT_PUBLIC_FRAME_TAGS || ''}"`,
|
||||
`NEXT_PUBLIC_FRAME_BUTTON_TEXT="${buttonText}"`,
|
||||
|
||||
// Analytics
|
||||
`NEXT_PUBLIC_ANALYTICS_ENABLED="${process.env.NEXT_PUBLIC_ANALYTICS_ENABLED || 'false'}"`,
|
||||
|
||||
// Neynar configuration (if it exists in current env)
|
||||
...(process.env.NEYNAR_API_KEY ?
|
||||
[`NEYNAR_API_KEY="${process.env.NEYNAR_API_KEY}"`] : []),
|
||||
|
||||
@ -121,6 +121,7 @@ async function loadEnvLocal() {
|
||||
'NEXT_PUBLIC_FRAME_PRIMARY_CATEGORY',
|
||||
'NEXT_PUBLIC_FRAME_TAGS',
|
||||
'NEXT_PUBLIC_FRAME_BUTTON_TEXT',
|
||||
'NEXT_PUBLIC_ANALYTICS_ENABLED',
|
||||
'NEYNAR_API_KEY',
|
||||
'NEYNAR_CLIENT_ID'
|
||||
];
|
||||
|
||||
@ -4,6 +4,7 @@ import { useEffect, useState, useCallback } from "react";
|
||||
import sdk, { type Context, type FrameNotificationDetails, AddMiniApp } from "@farcaster/frame-sdk";
|
||||
import { createStore } from "mipd";
|
||||
import React from "react";
|
||||
import { logEvent } from "../../lib/amplitude";
|
||||
|
||||
interface FrameContextType {
|
||||
isSDKLoaded: boolean;
|
||||
@ -72,36 +73,54 @@ export function useFrame() {
|
||||
setContext(context);
|
||||
setIsSDKLoaded(true);
|
||||
|
||||
const amplitudeBaseEvent = {
|
||||
fid: context.user.fid,
|
||||
username: context.user.username,
|
||||
clientFid: context.client.clientFid,
|
||||
};
|
||||
const amplitudeUserId = `${context.user.fid}-${context.client.clientFid}`;
|
||||
|
||||
logEvent("Frame Opened", {
|
||||
...amplitudeBaseEvent,
|
||||
location: context.location,
|
||||
added: context.client.added,
|
||||
}, amplitudeUserId);
|
||||
|
||||
// Set up event listeners
|
||||
sdk.on("frameAdded", ({ notificationDetails }) => {
|
||||
console.log("Frame added", notificationDetails);
|
||||
setAdded(true);
|
||||
setNotificationDetails(notificationDetails ?? null);
|
||||
setLastEvent("Frame added");
|
||||
logEvent("Frame Added", amplitudeBaseEvent, amplitudeUserId);
|
||||
});
|
||||
|
||||
sdk.on("frameAddRejected", ({ reason }) => {
|
||||
console.log("Frame add rejected", reason);
|
||||
setAdded(false);
|
||||
setLastEvent(`Frame add rejected: ${reason}`);
|
||||
logEvent("Frame Add Rejected", amplitudeBaseEvent, amplitudeUserId);
|
||||
});
|
||||
|
||||
sdk.on("frameRemoved", () => {
|
||||
console.log("Frame removed");
|
||||
setAdded(false);
|
||||
setLastEvent("Frame removed");
|
||||
logEvent("Frame Removed", amplitudeBaseEvent, amplitudeUserId);
|
||||
});
|
||||
|
||||
sdk.on("notificationsEnabled", ({ notificationDetails }) => {
|
||||
console.log("Notifications enabled", notificationDetails);
|
||||
setNotificationDetails(notificationDetails ?? null);
|
||||
setLastEvent("Notifications enabled");
|
||||
logEvent("Notifications Enabled", amplitudeBaseEvent, amplitudeUserId);
|
||||
});
|
||||
|
||||
sdk.on("notificationsDisabled", () => {
|
||||
console.log("Notifications disabled");
|
||||
setNotificationDetails(null);
|
||||
setLastEvent("Notifications disabled");
|
||||
logEvent("Notifications Disabled", amplitudeBaseEvent, amplitudeUserId);
|
||||
});
|
||||
|
||||
sdk.on("primaryButtonClicked", () => {
|
||||
|
||||
34
src/lib/amplitude.ts
Normal file
34
src/lib/amplitude.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { APP_URL } from "./constants";
|
||||
|
||||
// Amplitude tracking -- only runs if configured via the CLI or in the .env file
|
||||
export function logEvent(
|
||||
eventType: string,
|
||||
eventProperties: Record<string, any> = {},
|
||||
deviceId: string | null = null
|
||||
) {
|
||||
if (process.env.NEXT_PUBLIC_ANALYTICS_ENABLED?.toLowerCase() !== 'true' || process.env.NODE_ENV !== "production") {
|
||||
return;
|
||||
}
|
||||
|
||||
const event = {
|
||||
event_type: eventType,
|
||||
api_key: '0c4fe46171b9bb8eca2ca61eb71f2e19',
|
||||
time: Date.now(),
|
||||
user_id: APP_URL,
|
||||
...(deviceId && { device_id: deviceId }),
|
||||
...(Object.keys(eventProperties).length && { event_properties: eventProperties })
|
||||
};
|
||||
|
||||
fetch('https://api2.amplitude.com/2/httpapi', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
api_key: '0c4fe46171b9bb8eca2ca61eb71f2e19',
|
||||
events: [event]
|
||||
})
|
||||
}).catch(error => {
|
||||
console.error('Amplitude tracking error:', error);
|
||||
});
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user