Tag manager
The Tag manager holds the marketing tags a shop runs. A tag is a registry entry or an https script, with the vendor it loads and the purpose it serves. Its triggers say on which page views or theme events it fires, and its variables fill the placeholders in its configuration. A change is never live on its own: the active tags, triggers and variables of a market are frozen into a container version, and a storefront runs only the latest published one. A version is frozen, carries a SHA-256 hash over its snapshot, and is never edited or deleted.
A publish is checked against the consent manager. Each marketing tag names a vendor and a purpose, and the publish is refused unless the consent policy discloses that vendor under that purpose. The same check covers the vendors a tag loads by itself. The app decides what may be published, not what may load: the storefront loads each tag only when the visitor's consent allows it. See Consent manager for the policy the check reads.
This page is for two readers:
- A storefront that loads the published container and, when it shows previews, the draft. Its calls are
GET /v1/tag-manager/delivery/containerandGET /v1/tag-manager/delivery/preview/{token}. - The merchant-side integration that manages tags, triggers and variables, validates and publishes containers, rolls back and keeps the check history. Its calls are the rest.
To set up a shop, go in this order:
- Read the registry with
GET /v1/tag-manager/registryto see which keys a registry tag may name, and the event names withGET /v1/tag-manager/vocabularies. - Make sure the consent manager has a published policy that discloses each vendor you will use under the right purpose.
- Create the variables, triggers and marketing tags:
POST /v1/tag-manager/variables,POST /v1/tag-manager/triggersandPOST /v1/tag-manager/tags, then attach triggers withPOST /v1/tag-manager/tags/{id}/triggers. SendX-Revenexx-Marketfor a market's tags (see The market header). - Check the draft with
POST /v1/tag-manager/container/validate. It lists every violation and writes nothing. - Publish it with
POST /v1/tag-manager/container/publish. - The storefront then reads the container from delivery.
Base path: https://api.revenexx.com/v1/tag-manager.
Each route needs its own scope, named after the route's capability, for example tag-manager.tags.create, or tag-manager.* for every route of the app. See Scopes. A key without the scope is refused with 403.
The list routes take limit (default 50, at most 200), offset and order (column.asc or column.desc). Each list filters by equality on its plain columns. Columns that hold JSON are answered but cannot be filtered.
Calls from the storefront
The storefront's calls go from its own server, the BFF, with an API key. They never come from the browser. See The BFF pattern for why, and Authentication for how the key is used.
The key needs tag-manager.delivery.container to read the published container. It also needs tag-manager.delivery.preview, but only if the storefront shows previews. Give the storefront key exactly these scopes, not tag-manager.*: the wildcard would also let it read and write the tags, triggers and variables and publish containers.
The container is cached at the gateway per tenant and market for 300 seconds. A publish drops the cached copy. A preview is never cached.
The market header
X-Revenexx-Market names the market a call is about. Tags, triggers and variables are market-scoped: a row written with the header belongs to that market and is visible only there, and a row written without it is global. Containers are published per market. Delivery answers the market's container, and falls back as described in Delivery.
The market also decides which consent policy a validate or publish is checked against. Validate, publish and the preview read work on the rows visible for the header they carry, so send the same header as the writes: a validate or publish without it builds the global container. The value is a market code: it is lowercased, starts with a letter or digit and holds letters, digits, - and _, up to 64 characters. A value outside that form counts as no market.
Tags, triggers and variables
A marketing tag is one of two kinds, set in kind: registry (an entry of GET /v1/tag-manager/registry, named in registry_key) or script (an https address, given in script_url). There is no custom HTML kind. Every tag needs kind, a code, a name, the vendor_code it loads and the purpose_code it serves. Vendors the tag loads by itself are not found by the app: you list them in chained_vendor_codes, and the publish check covers only that list. Other fields are description, config, event_map, load and is_active.
Tag and trigger codes hold lowercase letters, digits, - and _. Variable codes start with a letter and hold only lowercase letters, digits and _. A code is unique among the tags, among the triggers and among the variables. A create or edit that reuses one is answered 409 (code_taken). A PUT with no known field is answered 400 (empty_update).
loadisimmediate,idleorinteraction. A tag created without one takes the market'sdefault_loadsetting (scopemarket, defaultidle).configof a registry tag is checked against the registry key's configuration schema on every write. Therequiredlist of that schema, fromGET /v1/tag-manager/registry, names the options a tag must send, for most keys anid. It refusesdefaultConsent,name,email,user_id,user_hashandphone: the consent manager writes Consent Mode defaults, and a tag carries no personal data. Every key's schema also refuses properties it does not list. A value may be a{{code}}placeholder naming a variable. Onlyconstantvariables are substituted at publish, and only then is the config checked against the schema with the value filled in.event_fieldandpageplaceholders stay in the container as placeholders.- An inactive tag is kept but never published.
- A tag with no trigger loads on every page.
- Two tags cannot use the same registry key in one container: a publish with both is refused (
duplicate_registry_key).
A trigger is page_view (on page views that match its optional conditions: path_prefixes, page_types and b2b) or theme_event (when the named event of the theme event contract, theme-events/1, happens). Every trigger needs kind, a code and a name. A theme_event trigger also needs event_name, an event of that contract. A trigger can be attached to a tag once; a second attach is refused with 409 (already_attached). Deleting a trigger that is still attached to a tag is refused with 409 (trigger_in_use).
A variable is constant (a value kept in the variable), event_field (a field of the theme event) or page (a field of the page). Every variable needs kind, a code and a name. A constant variable also needs constant_value. The last two need a dotted path. Its code is the name a placeholder uses, as {{code}}.
| Operation | What it does |
|---|---|
GET /v1/tag-manager/tags | Lists the marketing tags visible in the market, paged. |
POST /v1/tag-manager/tags | Creates one marketing tag. Every broken rule is named in the 422. |
GET /v1/tag-manager/tags/{id} | Reads one marketing tag. |
PUT /v1/tag-manager/tags/{id} | Edits one marketing tag. The row it would leave is checked whole. |
DELETE /v1/tag-manager/tags/{id} | Deletes one marketing tag. |
GET /v1/tag-manager/tags/{id}/triggers | Lists the triggers attached to one tag. |
POST /v1/tag-manager/tags/{id}/triggers | Attaches one trigger to one tag. Body: trigger_id, the trigger's id (required; 422 when missing or unknown). A pair is attached once; a second attach is refused with 409. |
DELETE /v1/tag-manager/tags/{id}/triggers/{trigger_id} | Removes one trigger from one tag. |
GET /v1/tag-manager/triggers | Lists the triggers visible in the market, paged. |
POST /v1/tag-manager/triggers | Creates one trigger. Every broken rule is named in the 422. |
GET /v1/tag-manager/triggers/{id} | Reads one trigger. |
PUT /v1/tag-manager/triggers/{id} | Edits one trigger. The row it would leave is checked whole. |
DELETE /v1/tag-manager/triggers/{id} | Deletes one trigger. 409 while a tag still has it attached. |
GET /v1/tag-manager/variables | Lists the variables visible in the market, paged. |
POST /v1/tag-manager/variables | Creates one variable. Every broken rule is named in the 422. |
GET /v1/tag-manager/variables/{id} | Reads one variable. |
PUT /v1/tag-manager/variables/{id} | Edits one variable. The row it would leave is checked whole. |
DELETE /v1/tag-manager/variables/{id} | Deletes one variable. |
Registry and vocabularies
The registry lists every key a registry tag may name, with its label, category, the consent vendor code it usually discloses as, its hosts, the JSON Schema of its configuration and its default event map. Each configuration property carries English title and description, and x-title and x-description in German and English for the tag form.
The vocabulary lists the event names that a trigger or an event map may name, for the theme event contract theme-events/1, and the value sets of tags, triggers and variables.
| Operation | What it does |
|---|---|
GET /v1/tag-manager/registry | Lists the supported registry keys with their configuration schema and default event map. |
GET /v1/tag-manager/vocabularies | Lists the theme event names this app supports, plus the value sets of tags, triggers and variables. |
Containers: validate, publish, roll back
A container is the frozen set of the market's active marketing tags, their triggers and variables. Validate and publish run the same build and the same checks. Validate answers the list of violations and writes nothing. A publish with any violation is refused with 409 and the list in details.violations, and no version is created. Validate, publish, rollback and recheck answer 502 when the consent manager cannot be read, so nothing is checked or published against a policy nobody read.
Version numbers run across all markets, not per market.
The publish check names each broken case. These are the codes the check can return:
| Code | Refused when |
|---|---|
policy_missing | The consent manager has no published policy. |
undisclosed_vendor | A tag's vendor is not in the policy. |
purpose_not_served | The vendor is in the policy, but not under the tag's purpose. |
undisclosed_chained_vendor | A vendor the tag loads by itself is not in the policy. |
unknown_purpose | A tag's purpose is not in the policy. Checked only when the policy lists purposes. |
unsupported_registry_key | A registry tag names a key the registry does not list. |
invalid_kind | A tag has a kind other than registry or script. |
invalid_config | A registry tag's configuration breaks the key's schema. |
duplicate_registry_key | Two tags use the same registry key. |
script_not_https | A script tag's address is not https. |
unknown_variable | A placeholder names a variable that does not exist. |
unknown_event | An event map key or a trigger names an event that is not in theme-events/1. |
| Operation | What it does |
|---|---|
POST /v1/tag-manager/container/validate | Builds the draft for the market, reads the policy and answers every violation. Writes nothing. 502 when the consent manager cannot be read. |
POST /v1/tag-manager/container/publish | Freezes the draft of the market as the next container version. 201 with the version. 409 with container_violations and details.violations. 502 when the consent manager cannot be read. |
POST /v1/tag-manager/container/rollback | Publishes the snapshot of an earlier version as a new version, after the same checks against the policy published now for the old version's market. Body: version, the number to publish again (required; a missing or invalid one is 422). The X-Revenexx-Market header is ignored: the market is the old version's. The old version is not touched. 404 for an unknown number, 409 when it fails the checks, 502 when the consent manager cannot be read. |
GET /v1/tag-manager/container/status | Per market: the live version, its hash and policy version, and the latest check with its violations. |
GET /v1/tag-manager/container-versions | Lists the container versions, paged. |
GET /v1/tag-manager/container-versions/{id} | Reads one container version with its frozen snapshot and hash. |
A container version has no write route, so an edit or delete is answered with 405. A rollback is a new version, not a change to an old one.
Checks against new policies
Each live container is checked against the consent policy again when the consent manager publishes a version. The app receives the revenexx.consent_manager.policy_version.published event for this. The check changes no tag. It is stored as a container check with a reason of publish, policy_change or manual.
| Operation | What it does |
|---|---|
POST /v1/tag-manager/container/recheck | Checks every live container against the policy published now and records the result. Changes no tag. 502 when the consent manager cannot be read. |
GET /v1/tag-manager/container-checks | Lists the container checks, paged. Filters include ok, reason and container_version_number. |
GET /v1/tag-manager/container-checks/{id} | Reads one container check with its violations. |
Preview
A preview lets a storefront load the unpublished draft. The storefront page takes the token in its rvx_tm_preview URL parameter (the mint call returns that parameter's name as param, so the storefront URL is ?rvx_tm_preview=<token>). The token is answered once and stored only as its hash.
POST /v1/tag-manager/preview takes ttl_minutes, the lifetime in minutes: a whole number from 1 to 10080 (7 days). It defaults to 60. Send {} for the default.
| Operation | What it does |
|---|---|
POST /v1/tag-manager/preview | Mints a preview token. 201 with token, expires_at and param. 422 when ttl_minutes is out of range. |
GET /v1/tag-manager/delivery/preview/{token} | Builds the draft now for a valid token, and the token goes in the path. Never cached. An unknown and an expired token are both answered 404. |
Delivery
Delivery is what a storefront reads. A container's answer carries the active tags with their event maps and triggers, the variables, the market's tag settings and every third-party host, which the storefront needs for its Content-Security-Policy.
Delivery answers the market's latest published container. If the market has none, it answers the latest container published without a market. If there is none of those either, it answers an empty container with 200.
The container carries four of the app's settings with it. They are set per market or per tenant, as the scope column shows:
| Setting | Scope | Default |
|---|---|---|
event_price_basis | market | net |
data_layer_name | market | dataLayer |
push_events_to_data_layer | market | true |
first_party_mode | tenant | true |
| Operation | What it does |
|---|---|
GET /v1/tag-manager/delivery/container | Reads the latest published container for the market in the header, with active tags only. |
GET /v1/tag-manager/delivery/preview/{token} | Reads the draft by preview token. See Preview. |
Events
The app receives the consent manager's policy_version.published event, full name revenexx.consent_manager.policy_version.published, and rechecks the live containers. What the recheck does and records is in Checks against new policies. Event delivery itself is described in Events.