What gets stored
Referly writes at most three entries, all named after your program ID so that several programs can coexist on one domain without colliding:
So for a program with ID
abc123, you’re looking for abc123_affiliate_ref and abc123_affiliate_referral.
These two are the whole of Referly’s client-side state. The referral code answers “who gets credit”, the click ID answers “which visit was it”, and everything else — commission rates, cookie windows, affiliate details — lives on Referly’s side and is never written to the browser.
On a Shopify store the tracker additionally sets a cart attribute named
pushlap_affiliate_id on the visitor’s cart, so the click ID travels with the order through checkout. That’s a Shopify cart property, not browser storage, and it isn’t set anywhere else.Cookies first, localStorage as a fallback
At load, before anything else, the tracker checks what the browser will actually let it use. It writes a throwaway cookie calledplg_test, reads it back, and deletes it. If that round trip succeeds, cookies are used for everything. If it fails, the tracker tries localStorage with a plg_ls_test key and falls back to that instead. Both probes are cleaned up immediately, so you’ll never see them in DevTools unless you’re paused mid-execution.
The decision is made once per page load and applies to every read and write after it. If neither cookies nor localStorage are available — a locked-down browser, a strict privacy extension, an incognito context that blocks both — nothing persists, and every page view looks like a brand-new visitor.
Cookie attributes
When cookies are used, each entry is written like this:The tracker resolves your hostname down to its registrable domain using the public suffix list, then sets the cookie on a leading dot.
shop.your-domain.com and app.your-domain.com therefore share one attribution — a visitor who lands on your marketing subdomain and converts on your app subdomain is still credited correctly. Separate registrable domains do not share; that needs cross-domain tracking.Browsers reject
Secure cookies on plain HTTP. Your site must be served over HTTPS or nothing persists — the tracker will run, record the click, and then lose it on the next navigation. This is the usual reason tracking “works in production but not on http://localhost”.Storage is shared across your whole site, not scoped to the landing page.
The localStorage envelope
localStorage has no concept of expiry, so the tracker adds one. Each value is stored as JSON:
expires is a Unix timestamp in milliseconds. On every read the tracker compares it against the current time, and if it has passed, removes the entry and reports no attribution — the same outcome an expired cookie would produce. Reads that fail to parse are treated as no attribution rather than throwing.
Because this path is per-origin, localStorage attribution does not cross subdomains the way a cookie does. Visitors who end up on the fallback lose subdomain sharing.
How long it lasts
The duration comes from your program’s cookie window, fetched alongside the rest of your program configuration when a click is recorded. If that fetch fails — network error, ad blocker, Referly unreachable — the tracker falls back to 60 days so a failure degrades rather than breaks. Expiry is a sliding window, not a fixed one. Every time the tracker sees a returning visitor with stored attribution, it writes the entries again with a fresh expiry, so an actively engaged visitor doesn’t age out mid-consideration. One nuance worth knowing when you’re reasoning about exact dates: on the fast return-visit path — the visitor comes back with no referral parameter in the URL — the tracker refreshes storage before it fetches your program configuration, so that refresh uses the 60-day default rather than your configured window. Paths that do fetch your configuration use your configured window. If your window is shorter than 60 days, returning visitors get the longer one. Attribution and the cookie window covers the practical effect.When storage is cleared
Referly never clears storage on its own outside of those cases. In particular, a normal page view with no referral parameter leaves existing attribution alone.
Browser privacy limits
First-party storage written by JavaScript is not permanent, whatever expiry you set:- Safari (ITP) caps cookies written through
document.cookieat 7 days, and clearslocalStorageafter 7 days without interaction with your site. A 60-day window is effectively 7 days for those visitors. - Firefox in strict mode applies similar limits to storage it classifies as tracking-related.
- Chrome currently honours the full expiry for first-party cookies.
Inspecting and clearing while debugging
To see what’s there, open DevTools → Application, then Cookies (or Local Storage if the fallback is active) and filter on your program ID. From the console:.your-domain.com is not removed by deleting a same-named cookie scoped to www.your-domain.com — delete the one whose domain has the leading dot.
Debug mode logs which storage mechanism was chosen and every value read or written, which is usually quicker than reading storage by hand.
Related
Attribution and the cookie window
How long attribution lasts and who wins a conflict.
Install the snippet
The HTTPS and CSP requirements that make storage work.
Cross-domain tracking
Carrying attribution between separate registrable domains.
External click IDs
What the stored rsubID value is for.
Debug mode
Watch every storage read and write in the console.
Server-side tracking
Report conversions from your backend when browser storage isn’t enough.