Layers

Custom Events

What happens when you call track() with an event name outside the standard list.

View as Markdown

Use a custom event name when your action doesn't fit a standard event.

Naming rules

The SDK itself does not enforce a name format — any non-empty string is accepted. Recommended conventions:

  • snake_case.
  • Verb-noun: completed_onboarding, hit_streak_day_7.
  • Lowercase, no spaces or slashes.
  • Keep it short and stable — event names fragment dashboards when they drift.

What happens to custom events

SystemBehavior
sdk_events tableStored.
Layers Events pageShown.
Funnel / cohort analysisAvailable.
Meta CAPIDropped at the relay unless a per-app event_map override maps it to a standard Meta event.
TikTok Events APIDropped at the relay unless mapped via a per-app event_map.
Apple Search AdsNot involved — ASA uses install + post-install conversion signals, not SDK events.

The relay's default behavior is to forward only the events in the standard events mapping table. If you need a custom event to reach a platform, add a mapping in the ads layer's CAPI config (event_map).

Should I use custom for purchases?

No. Use purchase_success (or paywall_purchased) so Meta and TikTok see it as a standard Purchase event without any extra config. Add whatever extra context you want as custom properties:

layers.track('purchase_success', {
  revenue: 9.99,
  currency: 'USD',
  product_id: 'premium_yearly',
  transaction_id: 'txn_...',
  // custom properties:
  promo_code: 'SAVE20',
  acquisition_source: 'youtube_referral',
});

Volume considerations

There's no Layers-side limit on custom event names. Meta limits per Pixel to 10 standard + 40 custom event types across your ad account — if you expose thousands of fine-grained custom events and try to map them all, Meta will start dropping.

Best practice

Define a controlled vocabulary in your codebase:

// events.ts
export const Events = {
  ONBOARDING_COMPLETED: 'onboarding_completed',
  STREAK_HIT: 'streak_hit',
  REFERRAL_SENT: 'referral_sent',
} as const;

layers.track(Events.STREAK_HIT, { day: 7 });

Avoid free-form event names emitted from different call sites with slight variations — they fragment dashboards and make downstream analysis painful.

On this page