Code

Every file in a Transformation is an async function that receives a params object and returns an object describing what EdgeTag should do with the event. This page is the reference: what's in params for each file, what you can return, and what each return shape actually does.

You never write wrappers, imports, or exports — only the function body.

The return shape

Every file returns a plain object. Any combination of these fields is valid:

return {}                                     // no-op (pass through)
return { payload }                            // modify the event
return { skipEvent: true }                    // drop the event
return { additionalEvents: [event1, ...] }    // fan out extra events
return { user }                               // update user data (edge only)
return { payload, additionalEvents }          // combine any of the above

Returning nothing at all is equivalent to return {}.

tagRoot

Runs on the edge once per event, before any channel routing. Use for global rules — drop an event everywhere, enrich every payload, and emit an additional event based on attribution.

Available on params:

  • payload — the event: eventName, eventId, sdkVersion, locale, search, referrer, data (standard event fields).

  • user — hashable PII (email, phone, firstName, lastName, zip, …), or null.

  • variables — your Secrets as a plain object.

  • configuration — any configuration attached to the event.

  • platform — e.g. SHOPIFY, CUSTOM.

  • userCustomData — custom tags attached via the SDK.

  • hostData — request metadata (userAgent, ip, country, city, region, timezone, …).

  • logger.log(...), logger.error(...).

  • userKey.getFirstClick(), userKey.getLastClick() — paid-media attribution helpers.

  • providerData — raw click IDs and UTMs captured for this user.

tagChannel

Runs on the edge once per provider channel. Same params as tagRoot, plus:

  • providerId — the channel being processed (e.g. 'facebook', 'google', 'tiktok').

Use for provider-specific rules.

tagInstance

Runs on the edge once per provider instance (for example facebook||pixel1), the most granular edge level. Same params as tagChannel, including providerId. Use when you have multiple pixels or accounts inside a provider and need different behavior for each.

clientTagRoot

Runs in the browser once per event, before any provider tag fires.

Available on params:

  • payloadeventName, eventId, data.

  • user — reserved for browser user data (currently empty).

  • settingsuserId, sessionId, geoCountry, geoRegion, isEURequest, ip, consent, consentCategories, userProperties.

  • variables — only the Secrets you've flagged as client-side.

clientTagChannel / clientTagInstance

Same as clientTagRoot, plus providerId. Use these for browser-side provider- or instance-specific rules — for example, skipping a provider's browser pixel for EU traffic.

Two helpers on edge params make paid-media attribution easy. Both are easy to misuse, so read carefully.

params.userKey.getFirstClick() and getLastClick()

Returns a provider ID string or null. The provider ID tells you which paid channel drove this user; it is not a click ID, a URL, or a query string.

Valid return values are literal strings from a fixed set: 'facebook', 'googleAdsClicks', 'bing', 'snapchat', 'tiktok', 'twitter', 'linkedIn', 'pinterest', 'reddit', 'appLovin', 'taboola', 'outbrain', 'trybe', or null.

params.providerData

The raw click IDs and UTM values captured for this user, keyed by provider and then by the original query-parameter name:

An empty providerData means no paid-media clicks or UTMs were ever captured for this user.

circle-exclamation

What a Transformation can do

The four capabilities described at the top — modify, skip, fan out, update user — cover every real use case. Here's one real example of each.

1

Modify a payload

Enrich every Purchase event with a server-side source field and a USD-converted value. Always use structuredClone() before mutating the payload so you never touch the input.

2

Skip an event

Drop PageView events so they never reach any channel, and separately skip Facebook's browser pixel for visitors from the EU.

3

Create new events

When a Purchase happens, and the user's first or last paid-media click was Facebook, fan out a second Purchase_Facebook event alongside the original. This is where userKey and additionalEvents work together.

circle-info

additionalEvents is honored from tagRoot on the edge and clientTagRoot in the browser. Each additional event then goes through channel routing like any other event.

Combining capabilities

A single return can do more than one thing. This example enriches the payload and emits an additional event for Facebook-attributed purchases in the same call:

Return-value reference

Field
Type
Effect

payload

event object

Replace the event payload for this level.

user

user object or null

Replace user data for this level. Edge only.

additionalEvents

array of event objects

Emit extra events. Root-level only (tagRoot, clientTagRoot).

skipEvent

boolean

true drops the event at this level.

What's not available

Transformations are pure event transforms — by design, they don't:

  • make outbound HTTP requests (requestHandler is not available)

  • write to the identity graph (userSave, userGet, providerSave are not available)

  • access storage bindings (infra is not available)

If you need any of those, use a Destination.

Last updated

Was this helpful?