Custom events
Send your own events, such as an add-to-cart, a login, or a signup, from the tracker, a click, the GA4 dataLayer, or a single POST.
An event records a step without a URL of its own: an add-to-cart from a drawer, a login, a search, a newsletter signup. It is a name and, optionally, up to 30 properties.
From the tracker
Call fastmon.event with a name and the properties:
fastmon.event('add_to_cart', { value: 129.9, currency: 'EUR', sku: 'SW-100' });The event rides on the next beacon of the pageview. Without one within about a second, the tracker sends an event_update beacon by fetch, at most 20 per pageview. At page hide, pending events also go by keepalive fetch, and the collector keeps one copy.
A call before the tracker has loaded needs this queue stub first. The tracker sends what it queued with its first beacon.
<script>
window.fastmon = window.fastmon || {};
fastmon.event = fastmon.event || function () { (fastmon._q = fastmon._q || []).push(arguments); };
</script>From a click
A click on an element with data-fm-event, or on anything inside it, sends an event with that name. Every other data-fm-event-* attribute becomes a property, its value always a string.
<button data-fm-event="add_to_cart" data-fm-event-sku="SW-100" data-fm-event-value="129.9">
Add to cart
</button>The closest element with the attribute decides. An empty data-fm-event="" keeps clicks inside a marked container from counting.
From the dataLayer
Two independent application settings, both off by default, read pushes on window.dataLayer. Pushes before the tracker loaded count too, Google Tag Manager's gtm.* pushes never do.
collection.ga4_ecommercereadsview_item,add_to_cart,remove_from_cart,view_cart,begin_checkout,add_payment_info, andpurchasewith their ecommerce props.collection.data_layerreads every push that carries an event name. The event has no props unless you list top-level keys incollection.data_layer_prop_keys, up to 30.- Repeats: one name counts at most 10 times per pageview.
A GA4 event keeps value, currency, the number of items as item_count, and per item items.<n>.item_id, item_name, price, and quantity. A large order keeps at least its first six items. The order id and every other field stay in the page.
view_cart, begin_checkout, and purchase also reach their checkout funnel stage.
Keep or drop names
collection.data_layer_mode and collection.data_layer_names filter dataLayer events at the collector. A change applies within five minutes.
block(default) drops the listed names. With an empty list nothing is dropped.allowkeeps only the listed names, the GA4 names included. An empty list keeps no dataLayer event.- List: up to 50 names, and
eec.*covers every name starting witheec..
fastmon.event() calls and data-fm-event clicks are never filtered.
Without the tracker
Any script on your pages, a tag manager included, can post a single event. Send it as text/plain to avoid a preflight.
POST https://fastmon.site/c/e/{collector_hash}
Content-Type: text/plain
{"u": "https://shop.example/cart", "n": "add_to_cart", "p": {"value": 129.9, "currency": "EUR"}}| Key | Required | Meaning |
|---|---|---|
u | yes | The page URL. Its host picks the site. Stored like a pageview URL. |
n | yes | The event name. |
p | no | The properties, an object. Nested objects flatten to parent.child. |
ts | no | When it happened, epoch milliseconds. Defaults to the receive time. |
pvid | no | The pageview it belongs to. Without it the event joins no pageview and only counts. |
sq | no | Counts your events of one pageview from 1. Without it each event gets a random one. |
The route answers 204 whatever the body holds. A body that breaks a rule is dropped silently. Two posts with the same pvid, ts, and sq are one event, so a retry should carry its sq.
When the POST is blocked, GET /c/e/{collector_hash}.gif takes the same keys in the query string, with p as the JSON text of the object.
Browsers only
Country, device, and bot verdict come from the request, so a post from your server counts as a bot.
Limits and rules
| Rule | Value |
|---|---|
| Name | a-z, 0-9, _, ., -, 1 to 48 characters after lowercasing, at least one letter or digit |
| Events per beacon | 20, the rest is lost |
| Events per pageview | 100, the tracker sends no more |
| Property keys | 30 after flattening |
| Key length | 128 characters |
| Value length | 500 characters |
- Name cleanup: the tracker turns every other character into
_, soAdd To Cartis stored asadd_to_cartandGrößeasgr_e. It skips a name with no letter or digit left./c/e/rewrites nothing and drops an invalid name. - Over a limit: the whole event is dropped, and the beacon carrying it is kept.
- Types: a number or a boolean is stored as text, an array as its JSON text.
- Revenue: name the properties
valueandcurrency. Nothing converts or checks a currency. - Sampling: events are never sampled, not billed, and not capped per site.
- Off switch: the application setting
event_trackingturns your own events off.
Privacy
Names and properties must not hold personal data. The tracker masks keys and email addresses as described under Privacy → Event properties.
Correct or delete an event
Owners and members fix a wrong name, a wrong value, or a test purchase on one event. Open its row on the Events tab, or call PATCH /sites/{site_id}/events/{event_id} with the new name or properties. DELETE on the same path removes it.
The event_id comes from the event list. Every count and list follows, and the audit log records event.updated or event.deleted. Stage events derived from checkout pages cannot be changed and answer 409.
Where events show up
The page sits under Explorer → Events in the sidebar.
- Overview tab: events over time by name, the names ranked, and the most frequent values of each property.
- Revenue: one order per pageview with
order_placedorpurchase, at its largestvalue, per currency. A reloaded thank-you page counts again. - Value per event: the sum of
valueper name and currency. - Events tab: one row per event with its properties as chips. A row opens to every stored field and has a share link.
- Name filter: suggests the names of the period by count and accepts any valid name.
- Page filters: URL, page type, login state, connection, and viewport class narrow the events. Events stored before 2026-10-16 carry no page and match none.
- Visitor journey: shows a visitor's events with their properties. A
purchasecloses a visit likeorder_placed.
API
POST /organizations/{org_id}/analytics/eventslists events newest first, each withevent_id,name,source, andprops.namestakes any name, andsourceistracker,collector, orshopify_pixel. See the reference.POST /organizations/{org_id}/analytics/events/overviewcounts the events of a window per name, over time, and per property value, withorder_revenueandvalue_sums.revenueis deprecated.- MCP and Ask: the
get_eventstool answers the same counts. See MCP server.
Checkout funnel
Cart, checkout, and success per visitor, counted from stage events, with the shop's cart requests beside them. On by default; a Shopify shop adds a pixel for its checkout.
Network Error Logging
Failed requests to your site as the browser reports them itself, including pages that never loaded the tracker.