If your site publishes business events to window.dataLayer, because you set up Google Tag Manager for Google Analytics, those events already reach Skomi. There is nothing to rewrite, no adapter to install, and no second push to add beside the first.

This page is what happens, what does not, and the limits worth knowing before you rely on it.

Nothing to do

Install the snippet. Skomi hooks dataLayer and reads what is pushed to it.

Both shapes work:

// the object form
dataLayer.push({ event: 'purchase', value: 49.00, currency: 'EUR' });

// gtag, which pushes its own arguments rather than an object
gtag('event', 'purchase', { value: 49.00, currency: 'EUR' });

You can keep GTM. You can keep Google Analytics running beside Skomi while you compare them. That is the sensible way to migrate, and nothing here interferes with it.

Why it works whichever script loads first

GTM replaces dataLayer.push with its own wrapper when gtm.js finishes loading, and both scripts load asynchronously. Whichever landed second would plainly overwrite the other's wrapper and silently swallow its events.

Skomi installs push as an accessor instead, so GTM's assignment arrives in the setter and becomes the function Skomi delegates to. Ours stays in front however the race resolves. You do not have to order your tags.

What is captured

The event name, meaning event on the object, or the second argument to gtag.

Every property, flattened to dotted paths, because an event's properties are stored as text:

dataLayer.push({
  event: 'purchase',
  transaction_id: 'ORD-1234',
  value: 49.00,
  currency: 'EUR',
  ecommerce: { items: [{ item_name: 'Pro plan', price: 49.00 }] }
});

arrives as transaction_id, value, currency, ecommerce.items.0.item_name, ecommerce.items.0.price.

The monetary value, read from value or from ecommerce.value. Strings are accepted, because dataLayer values often arrive out of a template as text.

The currency, from currency or ecommerce.currency in the same way. A GA4 ecommerce event already carries { value, currency } together, so a site wired up for Google is sending Skomi a fully denominated purchase without knowing it.

The order id. The server reads transaction_id out of the properties, and a repeat of the same id is dropped rather than counted, which matters more than it sounds. A confirmation page fires on every load: a refresh, a back button, reopening the email a week later. Without an order id those are three sales.

What is not captured

GTM's own lifecycle events. Anything under the gtm. namespace, and the keys GTM uses to control its own dispatch: event, eventCallback, eventTimeout, eventModel, _clear. They say nothing about your business and would outnumber the real events several to one.

Anything beyond the limits. These are real and worth knowing before you discover them:

Limit Value
Properties per event 25
Nesting depth 3 levels
Property name 64 characters
Property value 255 characters
Order id 128 characters

A large ecommerce.items array will not fit. Each item contributes several properties, so an order of ten line items is well past twenty-five and the remainder is dropped rather than truncated per item. If line-item detail matters to you, it belongs in your shop's own reporting. Skomi records the order, its value and its currency, not its contents. There is no product dimension anywhere in the product.

Google's own integrations. Consent Mode signalling, audience export, Google Ads linking. Those are between GTM and Google and Skomi is not part of them.

Where the events show up

Under their own names, alongside the ones Skomi captures by itself. Each event records where it came from: datalayer for these, api for a hand-written skomi.track() call, auto for the outbound links and downloads Skomi captures without being asked, so you can tell an event you asked for from one you merely allowed.

Turn any of them into a goal to get a conversion rate against it.

If you would rather call it directly

skomi.track('purchase', { plan: 'pro' }, 49.00, 'EUR', 'ORD-1234');

Name, properties, value, currency, order id, with the last three optional. Use it for events that have no reason to go through GTM. A site that has no dataLayer at all does not need one.

Checking it worked

Push a test event from the console on the real domain:

dataLayer.push({ event: 'test_event', value: 1, currency: 'EUR' });

Then look for test_event in your events. If it is not there, work through what to check when the snippet is not working, and note that localhost collects nothing, because it is not the domain you registered.