Created
March 17, 2025 23:26
-
-
Save Enalmada/6ee99ff040b74d068e498f8bd568450c to your computer and use it in GitHub Desktop.
OpenPanel Custom Function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Handle track event | |
* @param {SegmentTrackEvent} event | |
* @param {FunctionSettings} settings | |
*/ | |
async function onTrack(event, settings) { | |
// Get client ID and secret from settings | |
const clientId = settings.clientId; | |
const clientSecret = settings.clientSecret; | |
// Special handling for screen_view events to match OpenPanel's format | |
let properties = event.properties || {}; | |
// Prepare the event data for OpenPanel | |
const payload = { | |
type: "track", | |
payload: { | |
name: event.event, | |
properties: properties, | |
userId: event.userId || event.anonymousId, | |
timestamp: event.timestamp || new Date().toISOString() | |
} | |
}; | |
// Add SDK information to match OpenPanel's format | |
payload.payload.sdk = "segment"; | |
payload.payload.sdkVersion = "1.0.0"; | |
// Prepare headers with authentication | |
const headers = { | |
'Content-Type': 'application/json', | |
'openpanel-client-id': clientId, | |
'openpanel-client-secret': clientSecret | |
}; | |
// Add IP address for geo-location tracking if available | |
if (event.context?.ip) { | |
headers['x-client-ip'] = event.context.ip; | |
} | |
// Add user-agent for device information tracking if available | |
if (event.context?.userAgent) { | |
headers['user-agent'] = event.context.userAgent; | |
} | |
try { | |
const response = await fetch('https://api.openpanel.dev/track', { | |
method: 'POST', | |
headers: headers, | |
body: JSON.stringify(payload) | |
}); | |
if (response.status >= 500 || response.status === 429) { | |
// Retry on 5xx (server errors) and 429s (rate limits) | |
throw new RetryError(`Failed with ${response.status}`); | |
} | |
if (!response.ok) { | |
throw new Error(`OpenPanel API responded with status: ${response.status}`); | |
} | |
} catch (error) { | |
if (error instanceof RetryError) { | |
throw error; | |
} | |
// Retry on connection error | |
throw new RetryError(error.message); | |
} | |
} | |
/** | |
* Handle identify event | |
* @param {SegmentIdentifyEvent} event | |
* @param {FunctionSettings} settings | |
*/ | |
async function onIdentify(event, settings) { | |
const clientId = settings.clientId; | |
const clientSecret = settings.clientSecret; | |
// Prepare the identify data for OpenPanel | |
const payload = { | |
type: "identify", | |
payload: { | |
userId: event.userId, | |
traits: event.traits || {}, | |
timestamp: event.timestamp || new Date().toISOString(), | |
sdk: "segment", | |
sdkVersion: "1.0.0" | |
} | |
}; | |
// Prepare headers with authentication | |
const headers = { | |
'Content-Type': 'application/json', | |
'openpanel-client-id': clientId, | |
'openpanel-client-secret': clientSecret | |
}; | |
// Add IP address for geo-location tracking if available | |
if (event.context?.ip) { | |
headers['x-client-ip'] = event.context.ip; | |
} | |
// Add user-agent for device information tracking if available | |
if (event.context?.userAgent) { | |
headers['user-agent'] = event.context.userAgent; | |
} | |
try { | |
const response = await fetch('https://api.openpanel.dev/track', { | |
method: 'POST', | |
headers: headers, | |
body: JSON.stringify(payload) | |
}); | |
if (response.status >= 500 || response.status === 429) { | |
// Retry on 5xx (server errors) and 429s (rate limits) | |
throw new RetryError(`Failed with ${response.status}`); | |
} | |
if (!response.ok) { | |
throw new Error(`OpenPanel API responded with status: ${response.status}`); | |
} | |
} catch (error) { | |
if (error instanceof RetryError) { | |
throw error; | |
} | |
// Retry on connection error | |
throw new RetryError(error.message); | |
} | |
} | |
/** | |
* Handle page event | |
* @param {SegmentPageEvent} event | |
* @param {FunctionSettings} settings | |
*/ | |
async function onPage(event, settings) { | |
const clientId = settings.clientId; | |
const clientSecret = settings.clientSecret; | |
// Get the page URL and title from the event | |
const path = event.properties?.url || event.context?.page?.url || ''; | |
const title = event.properties?.title || event.context?.page?.title || ''; | |
const referrer = event.properties?.referrer || event.context?.page?.referrer || ''; | |
// OpenPanel uses a track event with name "screen_view" for page views | |
const payload = { | |
type: "track", | |
payload: { | |
name: "screen_view", | |
properties: { | |
...event.properties, | |
__path: path, | |
__title: title, | |
__referrer: referrer | |
}, | |
userId: event.userId || event.anonymousId, | |
timestamp: event.timestamp || new Date().toISOString(), | |
sdk: "segment", | |
sdkVersion: "1.0.0" | |
} | |
}; | |
// Prepare headers with authentication | |
const headers = { | |
'Content-Type': 'application/json', | |
'openpanel-client-id': clientId, | |
'openpanel-client-secret': clientSecret | |
}; | |
// Add IP address for geo-location tracking if available | |
if (event.context?.ip) { | |
headers['x-client-ip'] = event.context.ip; | |
} | |
// Add user-agent for device information tracking if available | |
if (event.context?.userAgent) { | |
headers['user-agent'] = event.context.userAgent; | |
} | |
try { | |
const response = await fetch('https://api.openpanel.dev/track', { | |
method: 'POST', | |
headers: headers, | |
body: JSON.stringify(payload) | |
}); | |
if (response.status >= 500 || response.status === 429) { | |
// Retry on 5xx (server errors) and 429s (rate limits) | |
throw new RetryError(`Failed with ${response.status}`); | |
} | |
if (!response.ok) { | |
throw new Error(`OpenPanel API responded with status: ${response.status}`); | |
} | |
} catch (error) { | |
if (error instanceof RetryError) { | |
throw error; | |
} | |
// Retry on connection error | |
throw new RetryError(error.message); | |
} | |
} | |
/** | |
* Handle group event | |
* @param {SegmentGroupEvent} event | |
* @param {FunctionSettings} settings | |
*/ | |
async function onGroup(event, settings) { | |
const clientId = settings.clientId; | |
const clientSecret = settings.clientSecret; | |
// Prepare the group data for OpenPanel | |
const payload = { | |
type: "group", | |
payload: { | |
groupId: event.groupId, | |
traits: event.traits || {}, | |
userId: event.userId || event.anonymousId, | |
timestamp: event.timestamp || new Date().toISOString(), | |
sdk: "segment", | |
sdkVersion: "1.0.0" | |
} | |
}; | |
// Prepare headers with authentication | |
const headers = { | |
'Content-Type': 'application/json', | |
'openpanel-client-id': clientId, | |
'openpanel-client-secret': clientSecret | |
}; | |
// Add IP address for geo-location tracking if available | |
if (event.context?.ip) { | |
headers['x-client-ip'] = event.context.ip; | |
} | |
// Add user-agent for device information tracking if available | |
if (event.context?.userAgent) { | |
headers['user-agent'] = event.context.userAgent; | |
} | |
try { | |
const response = await fetch('https://api.openpanel.dev/track', { | |
method: 'POST', | |
headers: headers, | |
body: JSON.stringify(payload) | |
}); | |
if (response.status >= 500 || response.status === 429) { | |
// Retry on 5xx (server errors) and 429s (rate limits) | |
throw new RetryError(`Failed with ${response.status}`); | |
} | |
if (!response.ok) { | |
throw new Error(`OpenPanel API responded with status: ${response.status}`); | |
} | |
} catch (error) { | |
if (error instanceof RetryError) { | |
throw error; | |
} | |
// Retry on connection error | |
throw new RetryError(error.message); | |
} | |
} | |
/** | |
* Handle screen event | |
* @param {SegmentScreenEvent} event | |
* @param {FunctionSettings} settings | |
*/ | |
async function onScreen(event, settings) { | |
// For mobile apps - similar to page for web | |
const clientId = settings.clientId; | |
const clientSecret = settings.clientSecret; | |
// Get the screen name | |
const path = event.name || ''; | |
// OpenPanel uses a track event with name "screen_view" for screen views too | |
const payload = { | |
type: "track", | |
payload: { | |
name: "screen_view", | |
properties: { | |
...event.properties, | |
__path: path, | |
__title: path | |
}, | |
userId: event.userId || event.anonymousId, | |
timestamp: event.timestamp || new Date().toISOString(), | |
sdk: "segment", | |
sdkVersion: "1.0.0" | |
} | |
}; | |
// Prepare headers with authentication | |
const headers = { | |
'Content-Type': 'application/json', | |
'openpanel-client-id': clientId, | |
'openpanel-client-secret': clientSecret | |
}; | |
// Add IP address for geo-location tracking if available | |
if (event.context?.ip) { | |
headers['x-client-ip'] = event.context.ip; | |
} | |
// Add user-agent for device information tracking if available | |
if (event.context?.userAgent) { | |
headers['user-agent'] = event.context.userAgent; | |
} | |
try { | |
const response = await fetch('https://api.openpanel.dev/track', { | |
method: 'POST', | |
headers: headers, | |
body: JSON.stringify(payload) | |
}); | |
if (response.status >= 500 || response.status === 429) { | |
// Retry on 5xx (server errors) and 429s (rate limits) | |
throw new RetryError(`Failed with ${response.status}`); | |
} | |
if (!response.ok) { | |
throw new Error(`OpenPanel API responded with status: ${response.status}`); | |
} | |
} catch (error) { | |
if (error instanceof RetryError) { | |
throw error; | |
} | |
// Retry on connection error | |
throw new RetryError(error.message); | |
} | |
} | |
/** | |
* Handle alias event | |
* @param {SegmentAliasEvent} event | |
* @param {FunctionSettings} settings | |
*/ | |
async function onAlias(event, settings) { | |
const clientId = settings.clientId; | |
const clientSecret = settings.clientSecret; | |
// Prepare the alias data for OpenPanel | |
// Note: OpenPanel's API expects profileId and alias, while Segment uses userId and previousId | |
const payload = { | |
type: "alias", | |
payload: { | |
profileId: event.userId, | |
alias: event.previousId, | |
timestamp: event.timestamp || new Date().toISOString(), | |
sdk: "segment", | |
sdkVersion: "1.0.0" | |
} | |
}; | |
// Prepare headers with authentication | |
const headers = { | |
'Content-Type': 'application/json', | |
'openpanel-client-id': clientId, | |
'openpanel-client-secret': clientSecret | |
}; | |
// Add IP address for geo-location tracking if available | |
if (event.context?.ip) { | |
headers['x-client-ip'] = event.context.ip; | |
} | |
// Add user-agent for device information tracking if available | |
if (event.context?.userAgent) { | |
headers['user-agent'] = event.context.userAgent; | |
} | |
try { | |
const response = await fetch('https://api.openpanel.dev/track', { | |
method: 'POST', | |
headers: headers, | |
body: JSON.stringify(payload) | |
}); | |
if (response.status >= 500 || response.status === 429) { | |
// Retry on 5xx (server errors) and 429s (rate limits) | |
throw new RetryError(`Failed with ${response.status}`); | |
} | |
if (!response.ok) { | |
throw new Error(`OpenPanel API responded with status: ${response.status}`); | |
} | |
} catch (error) { | |
if (error instanceof RetryError) { | |
throw error; | |
} | |
// Retry on connection error | |
throw new RetryError(error.message); | |
} | |
} | |
/** | |
* Handle delete event | |
* @param {SegmentDeleteEvent} event | |
* @param {FunctionSettings} settings | |
*/ | |
async function onDelete(event, settings) { | |
// OpenPanel doesn't appear to have a specific delete API | |
throw new EventNotSupported('delete is not supported'); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
OpenPanel Integration for Segment
This gist contains code for a custom Segment Destination Function that forwards analytics data from Segment to OpenPanel. This allows you to continue using Segment's infrastructure while sending your data to OpenPanel instead of more expensive analytics platforms like Mixpanel.
Setup Instructions
1. Create a Destination Function in Segment
2. Configure Settings
In the Settings section of the function creation form, add the following JSON to define the required configuration parameters:
clientId string
clientSecret sensitive
3. Add the Function Code
In the Code section, paste the entire function code from this gist.
4. Save and Configure the Function
5. Test the Integration
What This Integration Supports
This custom destination function supports forwarding the following Segment event types to OpenPanel:
screen_view
events)screen_view
events)The integration also passes IP addresses and user agents to OpenPanel for proper geo-location and device tracking.
Troubleshooting
If events aren't appearing in OpenPanel:
Additional Resources