Sitelet https://ironfang.com/analytics/docs
Skip to content

Ironfang Analytics

Developer documentation

Follow each visit to your website as a session from the first page, with its journey, errors and failed requests, replay it in the portal with card numbers masked, see where visitors click and scroll in heatmaps, and read what each visitor's browser reported, over the portal or the API.

Quickstart

  1. In the portal, add a site with your website's origin, such as https://www.example.com.
  2. Publish the DNS TXT record the portal shows, then choose Verify. Verification asks your domain's own nameservers, so it passes as soon as the record is published.
  3. Turn recording on in the site's Settings tab.
  4. Add the install snippet from the Installation tab to every page. To stop recording a visitor, call the opt-out function from your consent banner or a link.

Sessions appear on the site's Sessions tab in the portal within seconds of a visit, with their recordings inside them.

Install, opt-out and consent

Copy the snippet from the site's Installation tab and add it once: it always loads the newest release, so you never need to change it to get one. It carries your site's public key.

<script async
  src="https://analytics.ironfang.com/sdk/loader.js"
  crossorigin="anonymous"
  referrerpolicy="no-referrer"
  data-site-key="ifa_site_..."
></script>

The snippet records from the first page load, and a recording is kept once the visitor interacts with the page: nothing is sent for a visitor who never does, crawlers are never recorded, and a visit shorter than five seconds is not kept or counted. To opt a visitor out, call this from your consent banner or a link, before or after the snippet loads. Recording stops, anything not yet sent is discarded in the browser, and the browser remembers the choice, so later pages do not record either:

window.ironfangAnalytics = window.ironfangAnalytics || [];
ironfangAnalytics.push(['setConsent', { replay: false }]);

If the visitor changes their mind, setConsent({ replay: true }) starts recording again.

Where the law requires consent before recording, as it usually does for visitors in the UK and the EU, turn on Ask for consent first in the site's Settings tab. The snippet the Installation tab then gives you carries data-consent="required": it makes no request and records nothing until your page calls setConsent({ replay: true }) once the visitor agrees. Deciding whether your visitors need to be asked is yours to do.

From release 0.6.0 the snippet also follows each visit as a session (see Sessions). Sessions are the root: a recording belongs to its session, so from release 0.6.1 a visitor is recorded only while their session is followed. Sessions follow the same consent as recording: where the site records unless the visitor opts out, a session is followed unless they opt out; where the site asks first, it starts once your page grants either. setConsent({ analytics: false }) refuses sessions, and recording with them; setConsent({ analytics: true, replay: false }) follows sessions without recording the visitor.

A page that must not be followed at all, such as one where visitors paste their own documents, calls pauseSession() as it opens (release 0.6.1): the page before it ends, and neither its address nor anything on it is reported or recorded. resumeSession() on the next page follows the visit and records it again. The session goes on in between, and the visitor's choices are untouched.

To mark a moment of the visit, such as a sign-up started or a checkout step, track it while the session is followed: it appears on the session's timeline. A name is up to 64 letters, digits, spaces and _ . : / -; up to ten properties go with it, each a lowercase name with text of up to 128 characters, a number, or true or false. Anything else is dropped. Send nothing that identifies the visitor.

ironfangAnalytics.push(['track', 'checkout started', { plan: 'pro', seats: 5 }]);

A visit across several pages in the same tab continues one recording. Once a recording starts, the browser also keeps a random visitor id in local storage and sends it with each new recording, so a second tab or a return visit can be found beside the first. It is made from nothing about the visitor, it is not a cookie, and opting out deletes it.

If your site has a Content Security Policy, allow https://analytics.ironfang.com in script-src and connect-src.

What is recorded

The page as it was displayed, and the scrolling, pointer movement, clicks and page changes on it. Masking happens in the visitor's browser, before anything is sent:

  • Anything that looks like a payment card number is masked wherever it appears: in page text, in a field or in an attribute. This is always on.
  • Card number, CVV, password and one-time-code fields are blocked: they appear as empty boxes of the same size. This is always on too.
  • With Mask form fields on, every field's value is replaced with placeholders, and so is text typed into an editable region (contenteditable). It is off for a new site.
  • With Mask all text on, page text is masked too; list selectors whose text is safe to show. It is off for a new site.
  • Regions matching your always-mask selectors have their text and fields masked either way.
  • Regions matching your block selectors, or carrying the rr-block class, are never recorded.
  • Recorded URLs never keep a fragment. They keep only the query parameters you list, such as utm_source, or, with Record all query parameters on, every parameter except the ones you list to remove, such as token.

To keep your own visits out of your recordings, list your home or office addresses under Excluded visitors in the site's capture settings: single addresses or ranges such as 203.0.113.0/24, or a network's /64 for IPv6. A visit from one is not recorded at all, and the settings page can add the address of the device you are using.

A session keeps each page's address, by the same query rules, when it opened and how long it was visible, when the tab was hidden and shown, and the events your page tracks. Its diagnostics are each a switch. Errors keeps uncaught errors and unhandled rejections: their name, a message with email addresses, card numbers and long numbers removed, the script's address and line, and the stack, cut to 12 frames whose addresses lose their query. Console errors keeps what your page passes to console.error, written out safely and scrubbed the same way. Failed and slow requests keeps requests that answer 400 or above, get no answer, time out or are aborted, resources that do not load, and anything taking 5 seconds or longer; Successful requests keeps the rest, or the share you choose. A request keeps its method, address, outcome, status where the browser gives one, and timing, and a query value named like a credential, such as a token or a signature, is replaced. Request and response bodies, headers and cookies are never read, and nothing is taken from the page's content.

Beside each recording Ironfang keeps the visitor's IP address and whether Cloudflare reported it, the full user agent, window and screen size, pixel ratio, language, time zone, country, the page they came from without its query and the browser's visitor id. All of it is deleted with the recording, and a session keeps the same details as long as its recordings do. Your privacy notice should say that you record sessions and keep these details, and that the browser keeps a visitor id.

Sites and origins

A site is one website: the origins its recorder may send from, a public collection key and what it captures. A public origin must be verified before it records: publish _ironfang-analytics.<host> as a TXT record with the value the portal shows. Loopback origins such as http://localhost:3000 need no record, for development.

The public key is safe to publish: it can only ask to record for its own site. Rotating it keeps the old key working for 24 hours so cached pages keep recording.

Sessions

A session is one visit: one browser on your site, across every tab it opens, from its first page until 30 minutes pass without the visitor doing anything, or 12 hours after it began. Its pages, tab activity, errors, requests and tracked events belong to it, and so do the recordings of its tabs.

With Follow every visit on in the site's Settings tab, a session is reported from the first page whether or not the visit is recorded: a visitor who never interacts, a visit past your allowance and a site with recording off still have their journey. Recording needs it: a recording belongs to its session, so turning it off turns recording off, and the API refuses recording without it. A new site has it on, with Errors and Failed and slow requests; a site made before release 0.6.0 that records follows sessions already, and turns on Errors and Failed and slow requests in Settings and moves its snippet to the current release.

The site's Sessions tab lists sessions by start, duration, entry page, pages and events, errors and failed requests, what can be replayed and whether the visitor is on the site now, with filters for each. A session opens on its journey: its pages in order, with the tab each was in and how long it was visible, each linked to that moment of the replay when it was recorded. Its events are grouped by page and filtered by type; its Network view lists its requests with what each came to, and its Errors view its errors, each once per page with how often it happened, both filterable and linked to that moment of the replay; its recordings play in place, and its heatmap shows the session's own clicks and scrolling on each page it recorded.

Pages and events are put in order by the browser's own clock, which every tab of a session shares, not by when they arrived. A batch sent twice is kept once, and one that arrives up to 2 minutes after the session ended still joins it; after that the browser starts a new session. A session keeps up to 300 pages and 1,500 events.

A recording that has expired or been deleted leaves its session in place: the journey and events stay, and the replay says the recording is gone.

From release 0.7.0 a request says what is known of how it ended: an answer, with its status; no answer, where the browser does not say why (offline, a name that did not resolve, a refused connection or a blocked cross-origin request); a timeout; an abort by your page, which is not counted as a failure; a cross-origin answer whose status the browser hides; or a script, image or stylesheet that did not load, where the browser does not say whether a server answered. Where the browser gives no status, none is shown.

Per page the snippet keeps at most 25 errors, 25 console errors, 50 failed or slow requests and 50 successful ones, and an error that happens again is counted rather than sent again. What these limits, the session's own and sampling leave out is counted, and the Network and Errors views say how much, so a partial list never reads as the whole.

Recordings

Every recording belongs to a session, one recording for each tab that was recorded, and in the portal recordings are found inside their sessions. Over the API, search recordings across every site by date, state, country, device class, browser, operating system, IP address or network in CIDR notation, entry path, any page visited and visitor id.

A recording whose visitor is on the site now is Live, and opens live: you see the page a moment behind them, and the view says how far, such as "~2.4s behind": their page looked as your screen does about 2.4 seconds ago. It is measured from their browser to yours, with the two clocks compared through ours, and never shown more precisely than that comparison allows. The view also says when it is catching up, paused, reconnecting or stale, and you can pause it and go back to live. While you watch, their browser sends what it records every second instead of every ten seconds, and a quiet page says every two seconds that nothing has changed, so it stays current; one that stops being heard from for ten seconds is marked stale. Nothing on their page changes, and nothing tells them anyone is watching. A recording that is still open but has not been heard from for 90 seconds is Inactive: the visitor has most likely left.

A recording is one browser tab on one site. It ends when the visitor leaves, after 30 minutes with nothing received, or at 60 minutes or 100 MiB, whichever comes first. Deleting a recording removes its replay and every detail kept with it at once.

Heatmaps

A heatmap totals the kept recordings of one page, on one kind of screen, over a period. A site's pages appear on its Heatmaps tab in the portal shortly after a recording that showed them ends, most visited first.

  • Clicks: where visitors clicked or tapped. Where the recorder reported where on a link or button a click landed (release 0.5.0 on), it is drawn there on that target in the page shown, whatever the width of the screen it came from; other clicks are drawn by their position.
  • Attention: how long each 50 px band of the page was on screen, as a share of each visit's time on the page. Idle time does not count, and nor does time with the tab hidden where the recorder reports it (release 0.5.0 on).
  • Scroll: the share of visits that reached each point of the page, with lines where 75%, 50% and 25% of them had stopped.
  • Movement: where the pointer rested. Phones and most tablets have no pointer.

Screens are taken separately by width, because a page laid out for one does not line up with another: mobile below 768 px, tablet from 768 px and desktop from 1,280 px.

Choose the last 7, 30 or 90 days, and compare with the period of the same length before it. A heatmap covers the recordings still kept, 28 days as standard, and at most 20,000 visits of a period: the same sample every time.

The page under the heat is a real visit, as it was in its first moments, before any click or typing, with your site's masking applied: one of up to 5 visits of the period's most common layout, which you can step through. The whole page is shown at that visitor's width, and you scroll it as any page. A section that only appears as a visitor scrolls shows as far as that visitor had got.

Heatmaps include only recorded visits: visitors who opted out, visits shorter than five seconds or with no interaction and visits past your allowance are not in them. The pointer is not where people look. Scrolling inside a panel, frames from other sites and canvas content are not covered.

Heatmaps show totals across visits. They are made from the recordings and deleted with them; a click keeps no text, and a page's address keeps no query string. For them the recorder adds only when the tab is hidden and the page's height, and stores nothing more in the visitor's browser.

API keys and scopes

Platform API keys are minted in the portal and start with if_live_. Send one as a bearer token; it acts only in the organisation it was minted for.

Authorization: Bearer if_live_...
  • analytics:sites:readRead sites, their origins, keys, settings history and installation state
  • analytics:sites:writeCreate and change sites, add and verify origins, rotate the public key
  • analytics:sessions:readSearch and read sessions with their pages and events, and recordings with their visitor details and playback batches, and read heatmaps
  • analytics:sessions:deleteDelete a session or a recording
  • analytics:*All Ironfang Analytics scopes

Errors

Every error is a JSON object with a stable code, a message for people and the request id to quote to support.

{
  "error": {
    "code": "not_found",
    "message": "no such object in this organisation",
    "docs": "https://ironfang.com/analytics/docs#errors"
  },
  "request_id": "01a0c375-7bae-7f02-a3d4-91e6b8c25f70"
}
StatusCodeMeaning
400invalid_query, invalid_jsonA query parameter or body is unknown, repeated or malformed.
401unauthorized, invalid_api_keyNo credential, or one that does not resolve.
403forbidden, insufficient_scopeThe key lacks the scope, or names another organisation.
404not_foundNo such object in this organisation, including an expired recording or session.
409conflict, version_conflictIt already exists, or the site changed since you read it.
422invalid_request, limit_reachedA field is invalid, or a limit on sites or origins would be exceeded.

Limits and retention

  • Recordings are kept 28 days from when they start, then deleted with every detail kept with them.
  • A session is kept for its site's session history: up to 90 days, and never less than its recordings; a new site keeps 90, and a site made earlier keeps sessions as long as its recordings until you change it. When the recordings' time is up, the session's IP address, user agent, visitor id, error messages and tracked event properties are removed; its pages and events stay for the rest of its time.
  • Every account can keep 5,000 recordings a month free. With Pay as you go switched on, recordings past that are charged at the published rates, within the monthly usage limit you set.
  • When the free allowance is used up without Pay as you go, or a usage limit is reached, new visits are not recorded until the allowance renews next month or the limit changes. Pages keep working and recordings already made are unaffected.
  • Up to 100 sites per organisation. A recording ends at 60 minutes or 100 MiB compressed.
  • Lists page with cursor and limit, up to 100 per page.

API reference

Base URL https://api.ironfang.com/analytics. The OpenAPI 3.1 document at https://api.ironfang.com/analytics/openapi.yaml carries every schema and error, with stable operation ids for generated clients.

EndpointScopeDoes
GET /v1/capabilitiesanalytics:sites:readWhat this deployment can do and the limits it applies.
GET /v1/sitesanalytics:sites:readList sites with their setup state.
POST /v1/sitesanalytics:sites:writeCreate a site with its origins.
GET /v1/sites/{siteId}analytics:sites:readGet a site with its configuration, origins and keys.
PATCH /v1/sites/{siteId}analytics:sites:writeChange a site against the version you read.
GET /v1/sites/{siteId}/config-versionsanalytics:sites:readList the site's settings history.
POST /v1/sites/{siteId}/originsanalytics:sites:writeAdd an origin.
DELETE /v1/sites/{siteId}/origins/{originId}analytics:sites:writeRemove an origin.
POST /v1/sites/{siteId}/origins/{originId}/verifyanalytics:sites:writeCheck the origin's DNS record.
POST /v1/sites/{siteId}/keys/rotateanalytics:sites:writeRotate the public key.
GET /v1/sites/{siteId}/installationanalytics:sites:readWhat the site still needs, and its install snippet.
GET /v1/sessionsanalytics:sessions:readSearch sessions across sites, newest first.
GET /v1/sessions/{sessionId}analytics:sessions:readGet a session with its journey and recordings.
GET /v1/sessions/{sessionId}/eventsanalytics:sessions:readGet a session's whole timeline, in order.
GET /v1/sessions/{sessionId}/heatmapanalytics:sessions:readGet a session's own heatmap for one of its pages.
DELETE /v1/sessions/{sessionId}analytics:sessions:deleteDelete a session with its recordings and every detail kept with them.
GET /v1/recordingsanalytics:sessions:readSearch recordings across sites.
GET /v1/recordings/{recordingId}analytics:sessions:readGet a recording with its visitor details and epochs.
GET /v1/recordings/{recordingId}/playbackanalytics:sessions:readList the batches that can be played, in order.
GET /v1/recordings/{recordingId}/chunks/{epoch}/{sequence}analytics:sessions:readOne batch of rrweb events.
DELETE /v1/recordings/{recordingId}analytics:sessions:deleteDelete a recording and every detail kept with it.
GET /v1/sites/{siteId}/pagesanalytics:sessions:readList a site's pages with visits in a period, by device.
GET /v1/sites/{siteId}/pages/changesanalytics:sessions:readList the days a page's layout changed.
GET /v1/sites/{siteId}/heatmapsanalytics:sessions:readGet a page's heatmap for one device and period.
GET /v1/sites/{siteId}/heatmaps/compareanalytics:sessions:readCompare a page's heatmaps for two periods.

Machine interfaces

InterfaceDetails
Product pagehttps://ironfang.com/analytics
Documentationhttps://ironfang.com/analytics/docs
API base URLhttps://api.ironfang.com/analytics
OpenAPI contracthttps://api.ironfang.com/analytics/openapi.yaml. The same contract is served as JSON at https://api.ironfang.com/analytics/openapi.json.
AuthenticationPlatform API key as a bearer token
Errorshttps://ironfang.com/analytics/docs#errors. A JSON body with a stable code, a message, this link and the request id.
MCPNot available. Not yet available over MCP. Sites, recordings, playback and deletion are in the portal and the REST API. MCP server reference; every tool and schema without a token at /.well-known/ironfang-mcp.json
Discovery/apis.json, /.well-known/api-catalog and /llms.txt