Guides
The Events tab at Developer > Console > Events is a read-only view of the events collection. It lists every create, update, and delete against your store's data as a per-field diff, with the acting user and a link to the originating request in Logs.
Nothing changed in the API. Everything the tab shows is available through GET /events, and this guide covers both.
Swell captures an event after each write to a model with events enabled, which is the default. The type is the model's event root plus the operation: product.updated, or product.variant.updated for a child collection. An updated event is written only when data actually changed.
| Field | Description |
| id | Event ID. IDs are time-ordered, so sort: 'id desc' is newest first. |
| model | Model path. Child collections use parent:child (products:variants); app models use apps/ |
| type | Event type, such as order.paid or setting.updated. |
| data | For created and deleted, the whole record. For updated, only the changed paths at their new values. |
| data.id | The record's ID. For settings, the section (checkout, payments) or, for app settings, the app ID. |
| user_id | The admin user who made the change. Absent for API keys, storefronts, apps, and background tasks. |
| req_id | The request that produced the event. Matches the request ID in Logs. |
| date_created | When the event was recorded, in UTC. |
Update events store only the changed paths. Arrays keep their full length with unchanged elements as null, so an index is the element's real position. Object elements carry their id.
{
"id": "68d0a4f1c1b2e3a4d5f60718",
"model": "products",
"type": "product.updated",
"data": {
"id": "66f1e9a0b3c4d5e6f7a8b9c0",
"price": 24,
"tags": [null, null, "clearance"]
},
"user_id": "5f3e2d1c0b9a8f7e6d5c4b3a",
"req_id": "68d0a4f0c1b2e3a4d5f60717",
"date_created": "2026-09-21T15:02:41.118Z"
}The tab renders this as price → 24 and tags[2] → clearance. Events never store previous values; the tab shows one only when an older event for the same record is already loaded.
The API masks credential-like keys on settings events. The tab and its export also mask any path ending in key, secret, token, password, pin, pem, passphrase, or signature, on every model.
Filters live in the URL query string.
| Filter | Query |
| Model | where.model = |
| Type | where.type = |
| User | where.user_id = |
| Date | where.date_created = { $gte, $lte } |
IDs are stored as ObjectIDs, which the API cannot regex-match. A 24-character hex search becomes an exact match on data.id, req_id, or id. Other text is sent as search, which matches model and type.
The list loads 50 events at a time, sorted id desc, and pages on an id cursor. Every filterable field is indexed, so the count is exact when a filter is set. Unfiltered, the API returns its maintained counter, which is approximate and labelled About.
To reconstruct one record's history:
const { results } = await swell.get('/events', {
where: { 'data.id': '66f1e9a0b3c4d5e6f7a8b9c0' },
sort: 'id desc',
limit: 50,
});Filter on req_id for everything one request changed, or on model, type, user_id, and date_created for the tab's other views. To page, add id: { $lt: lastId } to where. Keep sort: 'id desc' as a string: events have no default sort, and the cursor depends on it.
Export data under the list exports the matching events as CSV or JSON, paging at 1,000 per request and stopping at 10,000. Rows carry the event ID, date, label, type, model, record ID, user, app, request ID, notes, and changes, with sensitive values masked and changes capped at 50 fields per event.