Segment and RudderStack skill for Codex

One event plan, clean identity, every destination. Codex instruments apps with Segment or RudderStack from a tracking plan instead of ad hoc names, sends revenue and lifecycle events from the server with stable messageIds, and stitches anonymous visitors to users at login without merging people. Loading respects consent, server libraries flush before exit, and every new event is checked in the Source debugger and destination delivery views.

  • Integrations
  • $segment-cdp
  • 166 lines
  • 2 files
  • ~2,000 tokens
  • MIT
  • Updated

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- segment-cdp

Installs to ~/.agents/skills/segment-cdp/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $segment-cdp, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Implements customer event pipelines with Segment or RudderStack - Analytics.js 2.0 and server libraries, the identify/track/page/group calls, Object Action event naming, anonymousId to userId stitching, consent gating, server-side events for revenue, tracking plan enforcement and destination debugging. Use when instrumenting an app with Segment or RudderStack, cleaning up inconsistent event names, fixing broken user identity or duplicate events, moving tracking server-side, or checking why data is missing in a destination.

Use it when

  • Adding Segment or RudderStack tracking to a web, mobile or server app
  • Event names and properties are inconsistent across the codebase
  • Users are not stitched correctly between anonymous and logged-in sessions
  • Data is missing or duplicated in a downstream destination

Use something else when

How to check the result

Every new event shows in the Source debugger with the planned name and types, identity holds across login, and declining consent produces no requests to the CDP hosts.

The mistake it prevents

Calling identify with an email or a changing value as userId, which merges or splits people permanently in destinations.

~/.agents/skills/segment-cdp/SKILL.md

--- name: segment-cdp description: Implements customer event pipelines with Segment or RudderStack - Analytics.js 2.0 and server libraries, the identify/track/page/group calls, Object… license: MIT ---

Done well means: every event name and property comes from a written tracking plan, identity is stitched at login without merging different people, revenue and lifecycle events are sent from the server, nothing loads before consent where consent is required, and each event can be traced from the code to the Source debugger to the destination.

Inspect first

  1. Read AGENTS.md; then rg -n "analytics\.(track|identify|page|group)|@segment/|rudder" --glob '!node_modules'.
  2. Export the existing event names and properties from the code (or the Segment schema view) and compare them; inconsistent casing and duplicates are usually the first finding.
  3. Find the consent tool (OneTrust, Cookiebot, custom banner) and which regions require opt-in.
  4. Check whether a tracking plan exists ($analytics-tracking-plan writes one). Do not invent events without it; agree names with the user.

Choose where an event is sent from

Event typeSend fromWhy
Page views, UI clicks, client-only interactionsBrowser (Analytics.js)Only the client sees them
Signed Up, Order Completed, Subscription Started, Payment FailedServerAd blockers and closed tabs drop client events; the server knows the truth
Account / company traitsServer groupSingle source, avoids stale client state
Mobile app lifecycleMobile SDK (Analytics-Kotlin, Analytics-Swift, React Native)Automatic lifecycle events

Never send the same business event from both sides unless destinations are configured to use only one.

Naming and payloads

  • Events: Object + past-tense Action in Title Case: Product Added, Order Completed, Trial Started. Use Segment’s e-commerce and B2B SaaS spec names where they fit; destinations map them automatically.
  • Properties: snake_case, typed consistently (revenue always a number in major units, currency ISO 4217, IDs as strings).
  • Traits on identify describe the person (email, plan, created_at); properties on track describe the action. Do not put changing user state in every track.
  • Never put secrets, passwords, full card numbers or free-text fields that may contain them into events. Treat email and phone as personal data subject to the privacy policy.

Browser: Analytics.js 2.0

// analytics.ts
import { AnalyticsBrowser } from '@segment/analytics-next';

export const analytics = new AnalyticsBrowser();

export function startAnalytics(consented: boolean) {
  if (!consented) return;                       // gate load on consent where required
  analytics.load({ writeKey: import.meta.env.VITE_SEGMENT_WRITE_KEY });
}

// usage
analytics.page();
analytics.track('Product Added', { product_id: 'sku_18342', price: 189, currency: 'EUR', quantity: 1 });
  • Calls made before load are buffered and flushed after, so instrumenting first and loading on consent is safe.
  • Single-page apps: call analytics.page() on route change, not only on first load.
  • RudderStack equivalent: @rudderstack/analytics-js with rudderAnalytics.load(WRITE_KEY, DATA_PLANE_URL); the call API (track, identify, page, group) matches Segment’s.

Server: Node and Python

import { Analytics } from '@segment/analytics-node';

const analytics = new Analytics({ writeKey: process.env.SEGMENT_WRITE_KEY! });

analytics.track({
  userId: order.userId,
  event: 'Order Completed',
  messageId: `order-completed-${order.id}`,     // stable: dedupes retries
  timestamp: order.paidAt,
  properties: { order_id: order.id, revenue: order.total / 100, currency: order.currency },
});

process.on('SIGTERM', async () => { await analytics.closeAndFlush(); process.exit(0); });
import segment.analytics as analytics   # package: segment-analytics-python
analytics.write_key = os.environ["SEGMENT_WRITE_KEY"]
analytics.track(user_id, "Order Completed", {"order_id": oid, "revenue": 189.0, "currency": "EUR"})
analytics.flush()  # in scripts, jobs and serverless handlers before exit
  • Server libraries batch in memory. Serverless functions and short scripts must flush before returning or events are lost.
  • Use a deterministic messageId for events emitted by retried jobs or webhook handlers.
  • Pass the original timestamp when backfilling; otherwise all history lands on today.
  • Backfills of past data into production destinations are outward-facing and may trigger emails or ad audiences; confirm with the user and prefer a dedicated source.

Identity

  1. Anonymous visitors get an anonymousId from Analytics.js automatically.
  2. On sign-up or login call analytics.identify(user.id, { email, plan }) in the browser so the anonymous history links to the user. Use the internal immutable user ID, never email, as userId.
  3. Server events use the same userId. If the server must link a pre-login session, pass the browser’s anonymousId (read with analytics.user().anonymousId() and send it with the request).
  4. On logout call analytics.reset() so the next person on the device starts anonymous.
  5. B2B: analytics.group(accountId, { name, plan, employees }) after identify.

Shared devices and calling identify with the wrong ID merge two people irreversibly in many destinations; test identity flows in a dev source first.

  • Map consent categories (analytics, advertising, functional) to destinations. Segment Consent Management and RudderStack consent settings can filter destinations by category; the stricter option is not loading the library until consent.
  • Record consent changes as an event (Consent Updated) only if the tracking plan allows it.
  • Server-side events still need a lawful basis; check with the user’s privacy owner for regions that require opt-in.

Tracking plan enforcement

  • Segment Protocols or RudderStack Tracking Plans can block or flag unplanned events and wrong types. Turn on “flag” first, review violations for a week, then “block”.
  • Wrap calls in a typed helper so the compiler enforces the plan:
type Events = {
  'Product Added': { product_id: string; price: number; currency: string; quantity: number };
  'Order Completed': { order_id: string; revenue: number; currency: string };
};
export const trackEvent = <K extends keyof Events>(name: K, props: Events[K]) => analytics.track(name, props);

Segment Typewriter generated this from a plan in the past; a hand-written map like the above is lighter and easy to keep in sync.

Verification

  • Each new event appears in the Source Debugger with the planned name, property types and the expected userId / anonymousId.
  • A login flow shows the same anonymousId before and after identify, then the userId.
  • Declining consent results in no requests to api.segment.io / cdn.segment.com (or the RudderStack data plane) in the network tab.
  • Server events from a retried job show one event per messageId in the destination.
  • For each destination, the Event Delivery view shows successes for the new events; fix mapping errors there rather than changing the source payload blindly.

Gotchas

  • Ad blockers block the default CDN and API hosts; a custom domain proxy or server-side sending for key events recovers them.
  • revenue sent in cents in one place and in major units in another breaks every revenue report.
  • Calling identify on every page with unchanged traits wastes volume (MTU and event billing).
  • Device-mode destinations load third-party scripts in the browser; cloud-mode keeps them off the page.
  • Renaming an event creates a new one in every destination; plan migrations with both names for a transition period.

Output

Report: events added or renamed (name, source, properties), identity flow, consent behaviour, destinations affected, and debugger evidence for each event.

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Segment and RudderStack"
  short_description: "One event plan, clean identity, every destination"
  default_prompt: "$segment-cdp Instrument our signup and checkout funnel with Segment"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc
New

Introducing Codex Skills Pro

79 professional skills that take Codex through complete engagements, each with its own scripts, references and a report that verifies the result.

All-AccessOne-time payment, no subscription
$49
Get All-AccessOr browse individual skills from $2.99 →

Secure checkout by Creem