# Sporetag > Sporetag is the analytics and attribution agencies use to prove results, keep clients and automate follow-up. It ties ads and branded short links to the sales they bring, sends conversions to the Meta Conversions API, builds dashboards and scheduled client reports, runs email automations, and keeps visitor and customer profiles. Privacy-friendly website analytics is built in. A basic Free plan exists to try the stats. Facts: - Private mode (the default) sets no cookies and stores nothing in the browser. Visitor IP addresses are never stored. - 90-day tracking is opt in per site. It keeps a first-party id on the customer's own domain for 90 days and may need consent. - Live in v1: analytics, short links on go.sporetag.com or a custom domain, platform presets for SMS, email, social, ads, QR and print, saved UTM presets, per-ad URL templates for Meta, Google, TikTok and Microsoft ads, QR codes, named dashboards with a goal picker and a share link each, client dashboards and client invites with no password, client reports by email on a schedule with a live link and a PDF, email automations (triggers, waits, if or else paths, emails, tags, signed webhooks), anonymous visitor profiles with 90-day tracking that become customers when they give an email, Sporetag Assistant (every change waits for Apply), a cookie banner that follows the site theme, two-step sign-in with a sessions list and security emails, an Events API (POST https://sporetag.com/api/v1/events), a read API with read-only keys (GET https://sporetag.com/api/v1, OpenAPI at https://sporetag.com/api/v1/openapi.json, CSV feeds for Google Sheets), a remote MCP server for AI assistants (https://sporetag.com/mcp), a script proxy, the Meta Conversions API, an attribution report by source, campaign, ad, ad set or keyword, ad platform and short link, customer profiles, Stripe and Shopify connectors that bring orders, refunds and subscriptions into those profiles, a Stripe revenue view (new revenue, MRR with new, expansion, contraction and churn, lifetime value by source and campaign, refunds, time from first visit to first payment, and the share of payments tied to a visit), Klaviyo, Mailchimp and Attentive connectors, and a signed webhook out. - Short links: go.sporetag.com works at once on every plan. Paid plans can add their own short domain; the recommended pattern is a go subdomain of the customer's own site, like go.yourbrand.com, pointed at go.sporetag.com with one CNAME record. - Click ids read: gclid, gbraid, wbraid (Google), fbclid (Meta), ttclid (TikTok), msclkid (Microsoft), li_fat_id (LinkedIn), ScCid (Snapchat), epik (Pinterest), twclid (X), rdt_cid (Reddit). - A public live demo of the dashboard runs on a made-up shop at https://sporetag.com/demo, with demo data only. Read only, no sign-in. - A free UTM builder runs in the browser at https://sporetag.com/tools/utm-builder. Nothing typed there is sent anywhere. - The Events API, read API, MCP server, script proxy, attribution, Meta Conversions API and the Stripe and Shopify connectors are on paid plans only (Solo, Studio, Agency and Custom). Free has none of them. - Planned after v1, not live: Google Ads conversions, texts sent by automations, one-login HubSpot, GoHighLevel and Airtable connectors, one-click logins for Stripe, Shopify, Klaviyo and Mailchimp (keys are pasted today), ad spend logins for Google, TikTok, Microsoft, LinkedIn, Pinterest, Snapchat, X and Reddit, sending email from a customer's own domain, Search Console, history import from Google Analytics 4 (Plausible and Fathom export files import today). - Ad spend and return on ad spend are live on paid plans: Meta Ads connects with a Meta login or a token, and any platform (Google Ads included, until its connector ships) imports spend from a CSV file. - Prices are drafts and may change: - Free: $0. 1 site, 5,000 pageviews and clicks a month, 5 active short links, 30 days of history, 2 goals per site, no Events API or script proxy, no attribution or Meta Conversions API, 1 dashboard per site, no automations, 20 AI actions a month. - Solo: $29 a month or $290 a year. 5 sites, 100,000 pageviews and clicks a month, 250 active short links, 2 years of history, unlimited goals per site, Events API and script proxy, attribution and Meta Conversions API, 5 dashboards per site, 5 live automation flows per site, 25,000 anonymous visitor profiles per site, 200 AI actions a month. - Studio: $79 a month or $790 a year. 25 sites, 1,000,000 pageviews and clicks a month, unlimited active short links, 2 years of history, unlimited goals per site, Events API and script proxy, attribution and Meta Conversions API, 12 dashboards per site, 25 live automation flows per site, 50,000 anonymous visitor profiles per site, client dashboards, client invites and client reports, 1,000 AI actions a month, own logo. - Agency: $199 a month or $1,990 a year. 100 sites, 5,000,000 pageviews and clicks a month, unlimited active short links, 2 years of history, unlimited goals per site, Events API and script proxy, attribution and Meta Conversions API, 25 dashboards per site, 100 live automation flows per site, 100,000 anonymous visitor profiles per site, client dashboards, client invites and client reports, 3,000 AI actions a month, white label share pages and reports. - Custom: priced per deal, ask at https://sporetag.com/setup-call?plan=custom. Unlimited sites, unlimited pageviews and clicks a month, unlimited active short links, unlimited history, unlimited goals per site, Events API and script proxy, attribution and Meta Conversions API, 25 dashboards per site, 500 live automation flows per site, 100,000 anonymous visitor profiles per site, client dashboards, client invites and client reports, 10,000 AI actions a month, white label share pages and reports. - Overage: no hard stop. The first month over is free. From the second month in a row, 500,000 extra events cost $10. - Comparisons were checked October 2026. ## For AI assistants and agents - [Sporetag for AI assistants and agents](https://sporetag.com/ai.md): what Sporetag is in quotable facts, connecting Claude or ChatGPT, the read API and example prompts - [MCP server](https://sporetag.com/docs/mcp.md): a remote MCP server at https://sporetag.com/mcp (Streamable HTTP, read-only tools, a read key as a Bearer token) - [Read API](https://sporetag.com/docs/api.md): JSON over HTTPS at https://sporetag.com/api/v1 with read-only keys - [OpenAPI document](https://sporetag.com/api/v1/openapi.json): OpenAPI 3.1, no key needed - [Events API](https://sporetag.com/docs/events-api.md): send server-side events ## Docs - [Getting started](https://sporetag.com/docs/getting-started.md): Create an account, add your first site, paste one script tag and see your first visit in Sporetag. Then make your first short link. - [Dashboards](https://sporetag.com/docs/dashboards.md): Boards built for your site, a breakdown behind every number, cards that say why they are empty, monthly targets, and edits that save themselves. - [Assistant](https://sporetag.com/docs/assistant.md): Ask the assistant for goals, dashboards, links, segments, flows, client reports, emails and texts. Every change waits for your OK. - [Add the script](https://sporetag.com/docs/add-the-script.md): Paste the Sporetag script tag into your site's head. Steps for plain HTML, WordPress, Shopify, Webflow, Squarespace, Wix and single page apps. - [Install on Shopify](https://sporetag.com/docs/install-shopify.md): Add Sporetag to your Shopify store in about five minutes. Copy one line and paste it into your theme. No coding needed. - [Install on WordPress](https://sporetag.com/docs/install-wordpress.md): Add Sporetag to a WordPress site with the free WPCode plugin. Copy one line, paste it in the header box, and save. No coding needed. - [Install on Squarespace](https://sporetag.com/docs/install-squarespace.md): Add Sporetag to a Squarespace site with Code Injection. Copy one line, paste it into the Header box, and save. No coding needed. - [Install on Wix](https://sporetag.com/docs/install-wix.md): Add Sporetag to a Wix site with Custom Code in your site settings. Paste one line, place it in the head of all pages, and apply. - [Install on Webflow](https://sporetag.com/docs/install-webflow.md): Add Sporetag to a Webflow site. Paste one line into the Head code box in Site settings, save, then publish. No coding needed. - [Install on Framer](https://sporetag.com/docs/install-framer.md): Add Sporetag to a Framer site. Paste one line into the Custom Code section of Site Settings, then publish. No coding needed. - [Install with Google Tag Manager](https://sporetag.com/docs/install-google-tag-manager.md): Add Sporetag through Google Tag Manager with a Custom HTML tag on all pages. Use this if Tag Manager is already on your site. - [Install on any site](https://sporetag.com/docs/install-html.md): Add Sporetag to any website. Paste one line into the head of every page, or into the head code setting your site builder has. - [Your own tracking address](https://sporetag.com/docs/own-tracking-address.md): Load the Sporetag tag from a subdomain of your own site, like stats.yourdomain.com, with one DNS record. No proxy or code to run. - [Script proxy](https://sporetag.com/docs/script-proxy.md): Serve the Sporetag script and its event endpoint from your own domain with a tiny Cloudflare Worker, so ad blockers drop fewer of your visits. - [Tracking modes](https://sporetag.com/docs/tracking-modes.md): Private mode is cookieless with no banner. 90-day tracking keeps a 90-day first-party id so a sale ties back to an earlier click. How to choose. - [Cookie banner](https://sporetag.com/docs/cookie-banner.md): Turn on a simple Accept or Decline banner for your site with no code. Nothing is stored until a visitor accepts. You decide whether you need it. - [Bot filtering](https://sporetag.com/docs/bot-filtering.md): How Sporetag keeps bots, crawlers and automated browsers out of your numbers, and why visits from data centers still count as people. - [Autopilot](https://sporetag.com/docs/autopilot.md): Plain-English summaries, a simple view for clients, alerts that watch your sites, setup that runs itself and a weekly plan. - [Your week email](https://sporetag.com/docs/your-week.md): A short email every Monday morning with each site's visitors, top source and conversions, and the change from the week before. On every plan, off in one click. - [Custom events and goals](https://sporetag.com/docs/custom-events-and-goals.md): Count signups, purchases and button clicks with sporetag() custom events, then turn events and pages into goals you can see in the dashboard. - [Automatic events](https://sporetag.com/docs/automatic-events.md): Outbound link clicks, file downloads, 404 pages, scroll depth and form submits, counted with no code and free of your monthly allowance. - [Tracking health](https://sporetag.com/docs/tracking-health.md): One score per site that says whether you can trust its numbers, with a short list of checks and a one-tap fix for each. - [Funnels](https://sporetag.com/docs/funnels.md): See how many people make each step to a sale or a signup, where the rest leave, how long each step takes, and which sources finish best. - [Events API](https://sporetag.com/docs/events-api.md): Send signups and sales from your server to Sporetag with POST /api/v1/events and a per-site secret key. Examples in Node, Python, PHP and curl. - [Notes on charts](https://sporetag.com/docs/chart-notes.md): Mark launches, sales and changes on your chart. Sporetag adds notes for new goals, campaign starts and big days, and reports include them. - [Meta Conversions API](https://sporetag.com/docs/meta-conversions-api.md): Send conversions from Sporetag to Meta with the Conversions API. Paste a pixel id and access token, mark goals, test with a test event code. - [Attribution report](https://sporetag.com/docs/attribution-report.md): See conversions and revenue by source, campaign, ad platform and short link, under six attribution models, with each customer's path. - [Send results to your ad accounts](https://sporetag.com/docs/send-results-to-ad-accounts.md): Send leads and sales to TikTok, Pinterest, Snapchat and Reddit, and to Google Ads, Microsoft Ads and LinkedIn (when shipped), so their bidding learns. - [How did you hear about us](https://sporetag.com/docs/how-did-you-hear.md): Ask one optional question after a form or an order, and see the answers next to the source Sporetag tracked. - [Revenue and MRR](https://sporetag.com/docs/revenue-and-mrr.md): New revenue, MRR and what moved it, lifetime value by source and campaign, refunds and time to first payment, from Stripe, each with one plain sentence. - [Profit, blended ROAS and currencies](https://sporetag.com/docs/profit-and-currency.md): What every dollar on ads brought in sales, profit from the costs you give, and money in one currency at the European Central Bank's daily rate. - [Profiles](https://sporetag.com/docs/customer-profiles.md): One page per visitor and customer with every click, visit, email, text and sale, their first and last source, and lifetime value. Needs 90-day tracking. - [Import customers](https://sporetag.com/docs/import-customers.md): Bring in contacts from Klaviyo, Mailchimp, Shopify or a spreadsheet as a CSV file. Match the columns, then people are added or updated, never doubled. - [Cohorts and lifetime value](https://sporetag.com/docs/cohorts.md): See how many visitors come back, grouped by the week or month they first came and by their first source, and what customers from each source spend. - [Bring your data together](https://sporetag.com/docs/bring-your-data-together.md): One stream per customer from your site, your server and your other tools. What is automatic, what goes back to your tools, and how to send from any tool. - [Stripe connector](https://sporetag.com/docs/stripe-connector.md): Connect Stripe with a read-only key. Payments, refunds and subscriptions tie to the visits, ads and links that brought each customer, with MRR kept current. - [Shopify connector](https://sporetag.com/docs/shopify-connector.md): Connect a Shopify store with a custom app. Orders, refunds and customers join each customer profile, the attribution report and Meta. - [Klaviyo connector](https://sporetag.com/docs/klaviyo-connector.md): Connect Klaviyo with a private API key. Email and text activity joins each customer, and sources, value, best send hour and segments go back. - [Mailchimp connector](https://sporetag.com/docs/mailchimp-connector.md): Connect Mailchimp with an API key. Campaign sends, opens, clicks and unsubscribes join each customer, and Sporetag writes back merge fields and tags. - [Attentive connector](https://sporetag.com/docs/attentive-connector.md): Connect Attentive with a custom app. Text and email sends and clicks arrive by webhook, and Sporetag sends back custom attributes and segments. - [HubSpot and GoHighLevel](https://sporetag.com/docs/crm-connectors.md): Connect HubSpot or GoHighLevel with one login (when shipped). Won deals count as sales, and each profile goes back with where the person came from. - [Airtable](https://sporetag.com/docs/airtable-connector.md): Send each customer profile, with where they came from and what they spent, to an Airtable table (when shipped). Orders can get their own table. - [Webhooks out](https://sporetag.com/docs/webhooks-out.md): Post each customer profile, and optionally each order, to Zapier, Make, n8n or your own server. Signed, retried, and testable. - [Postscript connector](https://sporetag.com/docs/postscript-connector.md): Postscript limits its API to integration partners and enterprise shops, so there is no Postscript connector yet. What works today with UTM tags and webhooks. - [Segments and best send time](https://sporetag.com/docs/segments-and-best-send-time.md): Group customers by source, spend and activity, send groups to Klaviyo, Mailchimp or Attentive, and reach each person at the hour they are most likely to act. - [Automations](https://sporetag.com/docs/automations.md): Flows that act at the moments that matter: an email when someone signs up, a reminder when a checkout stalls, a note to you when a lead looks at pricing. - [Import your history](https://sporetag.com/docs/import-history.md): Bring past visits in from Google Analytics 4, Plausible or Fathom, so your charts are full on day one. What comes in, and how it is counted. - [Meta ad spend and ROAS](https://sporetag.com/docs/meta-ads-spend.md): Connect Meta Ads in one click to see what each campaign, ad set and ad cost next to the sales Sporetag credits, with Meta's own numbers beside ours. - [Email from your own domain](https://sporetag.com/docs/sending-domain.md): Send flow emails from you@yourbrand.com (when shipped), with replies on the person's profile and in your inbox. The DNS records, step by step. - [Get a texting number](https://sporetag.com/docs/texting-number.md): Your own number for flow texts (when shipped). Sporetag registers it with US carriers for you, shows the price first, and tells you where the review stands. - [Call tracking](https://sporetag.com/docs/call-tracking.md): Tracking numbers that show which ad, search or flyer made the phone ring (when shipped). Calls count as goals, join the caller's profile and reach your ads. - [Import ad spend from a file](https://sporetag.com/docs/csv-spend-import.md): Bring spend from Google Ads, TikTok, Microsoft, LinkedIn, Pinterest, Snapchat or any platform as a CSV file or a Google Sheets paste, to see return on ad spend. - [Messages](https://sporetag.com/docs/messages.md): One inbox for every site: replies to your flow emails and texts, what was sent and how it did, each person's stage, and writing back. - [Short links](https://sporetag.com/docs/short-links.md): Make short links on your own go. domain or go.sporetag.com, track each place you share them, and follow each click to the visit and the sale. - [UTM presets](https://sporetag.com/docs/utm-presets.md): Pick where you will share a link, like SMS, email, Instagram or Meta ads, and the UTM tags fill in. What each place sets, and how to save your own presets. - [QR codes](https://sporetag.com/docs/qr-codes.md): Every Sporetag short link has a QR code you can download as an SVG. Use the QR code preset so scans show up apart from clicks in your stats. - [Custom short domains](https://sporetag.com/docs/custom-short-domains.md): Put your short links on go.yourdomain.com, a go subdomain of your own site. Step by step for Cloudflare and any other DNS host, plus a Meta tip. - [Tracking ads and email](https://sporetag.com/docs/tracking-ads-with-utms.md): Track each ad in Meta, Google, TikTok and Microsoft ads with copy-ready templates, and SMS and email with the right link. Naming rules included. - [Client dashboards](https://sporetag.com/docs/client-dashboards.md): Share a read-only dashboard by private link or invite clients by email to sign in with no password. Agency makes it white label. - [Client reports](https://sporetag.com/docs/client-reports.md): Build an email report from your dashboard's numbers, charts and ads, then send it to clients weekly, monthly or both. - [Weekly reports](https://sporetag.com/docs/weekly-reports.md): The Monday email report now lives on each site's Reports tab, where you can also send monthly reports, add charts and ads, and pick who gets them. - [Overview, digest and uptime](https://sporetag.com/docs/agency-overview.md): Every client site on one page, the ones that need you first, a daily or weekly digest in email, Slack or Teams, and uptime, SSL and domain checks. - [The partner program](https://sporetag.com/docs/partner-program.md): For agencies on Studio and Agency. Get listed, earn up to a month of credit for each client that pays, and get help with your first three client sites. - [Data and privacy](https://sporetag.com/docs/data-and-privacy.md): What Sporetag records about your visitors, what it never stores, where the data lives, how long it is kept, and how to export or delete it. - [Billing and limits](https://sporetag.com/docs/billing-and-limits.md): What each Sporetag plan includes, what counts toward your monthly allowance, how overage works, and how to read, change or cancel your plan in Billing. - [Read API](https://sporetag.com/docs/api.md): Read stats, goals, attribution, ad spend and short links with a read key. JSON over HTTPS, OpenAPI 3.1, CSV feeds and copyable curl examples. - [MCP server for Claude and ChatGPT](https://sporetag.com/docs/mcp.md): Connect Claude, ChatGPT or another AI assistant to Sporetag with a read key, then ask how your site did last week in plain words. - [Google Sheets and Looker Studio](https://sporetag.com/docs/looker-studio.md): Put Sporetag numbers in Google Sheets with one formula that refreshes by itself, then chart them in Looker Studio. ## Guides Articles on analytics, UTMs, attribution and privacy, and platform tracking guides, written by the Sporetag team with dated sources. - [Why your analytics numbers never match](https://sporetag.com/guides/why-analytics-numbers-dont-match.md): GA4, Shopify, Meta and Google Ads count with different rules, dates and blind spots. Where each number splits, and which one to trust for each question. - [Meta ads vs Shopify: why purchases don't match](https://sporetag.com/guides/meta-ads-vs-shopify-sales.md): Meta Ads Manager shows more (or fewer) purchases than Shopify. The six causes, how to measure your own gap, and which number to use for budget calls. - [GA4 not tracking conversions: a checklist that finds the cause](https://sporetag.com/guides/ga4-not-tracking-conversions.md): Key events missing in GA4? Work through ten checks in order, from the event never firing to consent, filters, processing delays and Google Ads imports. - [Direct traffic: what (direct) / (none) really means](https://sporetag.com/guides/direct-traffic-explained.md): Direct traffic is every visit that arrived with no referrer and no tag. Where it really comes from, why it grows, and five ways to shrink it. - [GA4 "(not set)": every cause and how to fix it](https://sporetag.com/guides/ga4-not-set.md): Why GA4 shows (not set) for landing page, source, medium and campaign, how to tell which cause you have, and the fix for each one. - [Bot traffic in analytics: how to spot it and filter it](https://sporetag.com/guides/bot-traffic-in-analytics.md): How GA4 and other tools filter bots, the patterns that give bots away in your reports, and what you can do about the bots that get through. - [Cross-domain tracking: checkouts, booking tools and iframes](https://sporetag.com/guides/cross-domain-tracking.md): Why a visitor who moves to a checkout, a booking tool or an embedded form loses their source, and how to keep the credit with the ad that brought them. - [Leaving GA4 without losing your history](https://sporetag.com/guides/import-ga4-history.md): What you can take out of Google Analytics 4, what you cannot, the Data API limits, and why imported days never match a new tool's own numbers. - [Unassigned traffic in GA4: causes and fixes](https://sporetag.com/guides/ga4-unassigned-traffic.md): GA4 labels a session Unassigned when its source and medium match no channel rule. The rules, the tag values that fall through, and how to fix a spike. - [UTM parameters: the complete guide, with a naming scheme that holds up](https://sporetag.com/guides/utm-parameters.md): What each UTM parameter does, the naming rules GA4 actually applies, a scheme for source, medium and campaign, and the mistakes that break your reports. - [How to track your Instagram link in bio, through to the sale](https://sporetag.com/guides/track-instagram-link-in-bio.md): Instagram's own insights stop at link taps. How to see which bio link, story or post brought visits, signups and sales, with tags and a short link. - [gclid, fbclid and other click ids, explained](https://sporetag.com/guides/click-ids-explained.md): What gclid, gbraid, wbraid, fbclid, ttclid and msclkid are, what each one is for, how long they last, and why keeping them matters for ad tracking. - [How to track QR codes on print, packaging and signs](https://sporetag.com/guides/qr-code-tracking.md): A QR code sends no referrer, so scans show up as direct traffic. How to track scans, visits and sales per placement, and print codes that keep working. - [How to track email clicks and the sales they bring](https://sporetag.com/guides/track-email-clicks.md): Tag email links so every click and sale has a source, set it up in Klaviyo and Mailchimp, and spot the bot clicks that security scanners add. - [How to track SMS link clicks and the sales they bring](https://sporetag.com/guides/track-sms-link-clicks.md): Tag text message links so clicks and sales have a source, keep links short and on your own domain, and tell real taps from link preview clicks. - [Call tracking for local businesses: which ad made the phone ring](https://sporetag.com/guides/call-tracking-for-local-businesses.md): How call tracking numbers work, static numbers versus dynamic number insertion, how many you need, recording laws, and calls as conversions. - [Attribution models explained, with one buyer's path worked through](https://sporetag.com/guides/attribution-models-explained.md): First touch, last click, linear, position-based and data-driven attribution, worked through on one buyer path. What each model is good for, and its limits. - [Server-side vs client-side tracking: what each one sees](https://sporetag.com/guides/server-side-vs-client-side-tracking.md): Client-side tags run in the browser and miss what they cannot load. Server events come from your server. What each sees, costs, and when to use both. - [Meta Conversions API explained: setup, matching and deduplication](https://sporetag.com/guides/meta-conversions-api-explained.md): What the Meta Conversions API sends, which fields Meta needs, how deduplication with the pixel works, and the mistakes that double count or lose purchases. - [ROAS, blended ROAS and MER: which one to run the business on](https://sporetag.com/guides/roas-mer-blended-roas.md): Formulas for ROAS, blended ROAS, MER and break-even ROAS, a worked example, and why adding up each platform's ROAS overstates what your ads earn. - [Google Ads conversion tracking for lead generation sites](https://sporetag.com/guides/google-ads-conversion-tracking-lead-gen.md): Track forms, calls and the leads that become customers in Google Ads, with the right counting, values and windows so bidding learns from real sales. - [Offline conversions and enhanced conversions explained](https://sporetag.com/guides/offline-conversions-explained.md): How Google Ads and Meta accept sales and leads that happen off your website, how hashed email matching works, and the rules that make uploads fail. - [TikTok ads attribution: pixel, Events API and why numbers differ](https://sporetag.com/guides/tiktok-ads-attribution.md): How TikTok credits conversions, why TikTok Ads Manager reports more sales than GA4 or your store, and how the pixel and Events API work together. - [Lead-to-sale reporting: connect marketing sources to CRM revenue](https://sporetag.com/guides/crm-lead-to-sale-reporting.md): How to carry each lead's source into HubSpot or GoHighLevel, report won revenue by campaign, and avoid the mistakes that leave deals with no source. - [MRR and SaaS attribution: which channels bring revenue that stays](https://sporetag.com/guides/saas-mrr-attribution.md): How MRR is calculated, what moves it, how churn is measured, and how to tie subscription revenue to the campaigns that brought each customer. - [Klaviyo attribution windows vs your analytics](https://sporetag.com/guides/klaviyo-attribution.md): Klaviyo credits a sale to an email opened or clicked in the last 5 days. Why it runs above GA4 and Shopify, what to change, and which number to report. - [Break-even ROAS and target MER: the formulas, with a margin table](https://sporetag.com/guides/break-even-roas-and-target-mer.md): Break-even ROAS is 1 ÷ margin; target MER adds fixed costs and profit. Formulas, a lookup table by margin and worked examples you can copy. - [Meta Ads cost per lead and signups: what Meta counts, and what to pay](https://sporetag.com/guides/meta-ads-cost-per-lead.md): How Meta counts leads and signups, why Ads Manager's cost per lead differs from your CRM, and how to work out the most a lead is worth to you. - [Cookieless analytics and GDPR: what needs consent, and what usually does not](https://sporetag.com/guides/cookieless-analytics-gdpr.md): Do you need a cookie banner for analytics? How ePrivacy, the GDPR, the CNIL exemption and the UK change of 2026 apply to cookieless and cookie tracking. - [iOS and Safari tracking changes, version by version](https://sporetag.com/guides/ios-safari-tracking-changes.md): What Apple's Link Tracking Protection, ITP, App Tracking Transparency and Safari 26 remove, where each applies, and what still works for ad tracking. - [First-party data for small businesses: what to collect and why](https://sporetag.com/guides/first-party-data.md): The first-party data worth collecting, from orders and emails to how did you hear, what each is for, what to leave out, and the consent rules that apply. - [Bounce rate in GA4: what it means now, and when to worry](https://sporetag.com/guides/bounce-rate-ga4.md): GA4 defines bounce rate as the share of sessions that were not engaged. The rule, the formula, how it differs from the old one, and when it matters. - [Visitors, sessions and pageviews: how each tool counts them](https://sporetag.com/guides/sessions-users-pageviews.md): What a user, a session, a visit and a pageview are in GA4, Shopify and privacy-first tools, why the counts differ, and which one to report. - [Average session duration and time on page: how each tool measures it](https://sporetag.com/guides/session-duration-time-on-page.md): Why GA4, Universal Analytics and privacy tools report different session durations and time on page, the method each uses, and which to trust. - [How to set up goals and conversions without a developer](https://sporetag.com/guides/goals-without-a-developer.md): Four ways to count sales, leads, bookings and signups without writing code, how to do each in GA4, and the checks that keep a goal honest. - [Funnel analysis: find the step where people leave](https://sporetag.com/guides/funnel-analysis.md): How a conversion funnel is counted, open versus closed funnels, time windows, which drop-offs are normal, and how to read one without fooling yourself. - [Cohorts and retention: do the people you win come back?](https://sporetag.com/guides/cohort-retention-analysis.md): How a cohort table is built, how to read it by row, column and diagonal, three ways to count retention, and how to compare sources by customer. - [Ask your analytics in plain words: MCP and AI assistants](https://sporetag.com/guides/mcp-ai-assistants-analytics.md): What the Model Context Protocol is, how an AI assistant reads your analytics through it, what it answers well, and the safety rules for keys. - [Ecommerce dashboard template: the cards that matter, and who counts each](https://sporetag.com/guides/ecommerce-dashboard-template.md): An ecommerce dashboard template card by card: revenue, orders, conversion rate and MER first, which tool should count each number, and a worked month. - [Lead generation dashboard: what to show, and where each lead is counted](https://sporetag.com/guides/lead-generation-dashboard.md): A lead gen dashboard template: leads, lead rate, cost per lead and qualified leads by source, which tool counts each, and how to read a month. - [SaaS metrics dashboard: signups, MRR and the source of each customer](https://sporetag.com/guides/saas-metrics-dashboard.md): A SaaS metrics dashboard template: signups, cost per signup, MRR and its moves, lifetime value by source, plus MRR vs ARR and churn vs retention. - [Marketing dashboards for agencies: one for you, one for each client](https://sporetag.com/guides/marketing-dashboard-for-agencies.md): An agency needs two dashboards: a portfolio view that ranks clients by what needs attention, and a client board with three numbers and a target. - [Year over year comparison in analytics: same dates or same weekdays](https://sporetag.com/guides/year-over-year-comparison.md): YoY growth formula, when to compare 364 days back so weekdays line up, partial months, moving holidays, and what breaks a comparison with last year. - [Client reporting for agencies: a template clients actually read](https://sporetag.com/guides/client-reporting-for-agencies.md): What to put in a monthly client report, how often to send it, which numbers to lead with for stores and lead-gen clients, and how to explain gaps. - [Uptime monitoring for agency client sites](https://sporetag.com/guides/uptime-monitoring-for-agencies.md): What to monitor on every client site, how intervals and retries trade speed for false alarms, SSL and domain expiry, and reporting uptime. - [AI summaries in client reports, without made-up numbers](https://sporetag.com/guides/ai-client-report-summaries.md): How to use AI to write the summary at the top of a client report: what it should say, why models invent numbers, and a checking method that catches it. - [How to track a Shopify store: visits, sources and every order](https://sporetag.com/track/shopify.md): What Shopify's own analytics shows, where browser tags stop at checkout, and how to see each order with the ad, post or link that brought it. - [How to track a WordPress site without slowing it down](https://sporetag.com/track/wordpress.md): WordPress has no analytics of its own. How to add a light tracking tag with a header plugin, avoid cache problems, and count forms and WooCommerce sales. - [How to track a Webflow site: visits, sources and form leads](https://sporetag.com/track/webflow.md): Add analytics to Webflow with one line in Site settings, see which ads and posts bring form leads, and the plan and publishing rules that trip people up. - [How to track a Squarespace site beyond the built-in analytics](https://sporetag.com/track/squarespace.md): What Squarespace Analytics shows, what it cannot tell you about ads and links, and how to add a tracking tag with Code Injection where allowed. - [How to track a Wix site: sources, leads and the custom code rules](https://sporetag.com/track/wix.md): What Wix Analytics covers, why custom code only runs on a published site with a connected domain, and how to see which campaigns bring leads. - [How to track a Framer site: sources, signups and campaigns](https://sporetag.com/track/framer.md): Framer's built-in analytics counts visits. How to add a tracking tag in Site Settings, see which campaigns bring signups, and avoid the preview trap. - [How to add analytics to a Next.js site, App Router and Pages Router](https://sporetag.com/track/nextjs.md): Where to put an analytics script in a Next.js app, how client-side navigation affects pageviews, CSP rules, and sending conversions from route handlers. - [How to track GoHighLevel funnels and websites, from ad to booked call](https://sporetag.com/track/gohighlevel.md): Where the GoHighLevel tracking code goes, how to avoid double counting funnel steps, and how to see which ads bring leads, booked calls and won deals. - [How to track ClickFunnels: which ads bring opt-ins and sales](https://sporetag.com/track/clickfunnels.md): Where tracking code goes in ClickFunnels 2.0, how to avoid double counting, and how to tie opt-ins and sales to the ad that brought them. - [How to track a Kajabi site: sources for signups and course sales](https://sporetag.com/track/kajabi.md): Add a tracking tag to Kajabi with Header Page Scripts, why it does not run on checkout pages, and how to see which posts, emails and ads sell your courses. - [How to track a Ghost site: readers, members and paid signups](https://sporetag.com/track/ghost.md): Add a tracking tag to Ghost with code injection, count free and paid member signups, and see which posts, newsletters and links bring members. - [How to track a Carrd site: visits, sections and signups](https://sporetag.com/track/carrd.md): Add a tracking tag to Carrd with a hidden Embed element, why one-page sections count as one page, and how to count signups and link clicks. - [How to track a GoDaddy Website Builder site, and its limits](https://sporetag.com/track/godaddy.md): Where tracking code can go in GoDaddy Websites + Marketing, why code in an HTML section runs in an iframe, and how to measure leads and campaigns anyway. - [How to add tracking with Google Tag Manager, and when not to](https://sporetag.com/track/google-tag-manager.md): Add an analytics tag through Google Tag Manager with a Custom HTML tag, pick the right trigger, send events from triggers, and know the trade-offs. - [How to track Stripe Checkout and Payment Links sales by source](https://sporetag.com/track/stripe-checkout.md): Tie Stripe Checkout and Payment Links sales to the ad, email or post that brought the buyer, count each sale once, and stop Stripe showing up as a source. - [How to track WooCommerce sales by source, without a heavy plugin](https://sporetag.com/track/woocommerce.md): Count WooCommerce orders with their source three ways: the order received page, your Stripe account, or a server webhook, and what each one misses. - [How to track Calendly bookings as conversions, by source](https://sporetag.com/track/calendly.md): Count Calendly bookings as conversions in analytics and Google Ads, with UTM pass-through, embed events or a thank-you redirect, and no email in URLs. - [How to track a Substack: what it allows, and what it does not](https://sporetag.com/track/substack.md): Substack takes a GA4 Measurement ID and Meta and X pixel IDs, but no custom scripts. What each tracks, and how to measure the links that bring subscribers. - [How to track a beehiiv newsletter site: subscribers by source](https://sporetag.com/track/beehiiv.md): Add analytics to a beehiiv website through its Google Tag Manager field, count subscriptions from the confirmation page, and see which links bring readers. - [How to track Linktree clicks and the sales after them](https://sporetag.com/track/linktree.md): What Linktree's analytics, GA4 and Meta pixel integrations track, what they miss, and how to tie a bio link click to the sale on your own site. - [How to track Typeform submissions as conversions, by source](https://sporetag.com/track/typeform.md): Count Typeform submissions as conversions with the embed callback, pass UTM tags into hidden fields, and see which ad or post brought each response. - [How to track a BigCommerce store: tag, orders and sources](https://sporetag.com/track/bigcommerce.md): Add an analytics tag to BigCommerce with Script Manager, why to keep it off checkout under PCI DSS 4.0, and three ways to count orders with their source. - [How to track a Teachable school: sources for course sales](https://sporetag.com/track/teachable.md): Add a tracking tag to Teachable with Head Code Snippets, why it stops at checkout.teachable.com, and how to see which posts, emails and ads sell courses. ## Product - [Home](https://sporetag.com/) - [Pricing](https://sporetag.com/pricing) - [Product overview](https://sporetag.com/product) - [Dashboards](https://sporetag.com/product/dashboards) - [Client reports](https://sporetag.com/product/reports) - [Automations](https://sporetag.com/product/automations) - [Profiles](https://sporetag.com/product/profiles) - [Assistant](https://sporetag.com/product/assistant) - [How it works](https://sporetag.com/how-it-works) - [Live demo dashboard (demo data)](https://sporetag.com/demo) - [Sporetag for online store](https://sporetag.com/for/stores) - [Sporetag for services and leads](https://sporetag.com/for/leads) - [Sporetag for creators](https://sporetag.com/for/creators) - [Sporetag for agencies](https://sporetag.com/for/agencies) - [Book a setup call](https://sporetag.com/setup-call) ## Platforms - [Sporetag for Meta ads](https://sporetag.com/platforms/meta) - [Sporetag for Google Ads](https://sporetag.com/platforms/google) - [Sporetag for TikTok](https://sporetag.com/platforms/tiktok) - [Sporetag for Instagram](https://sporetag.com/platforms/instagram) - [Sporetag for Email](https://sporetag.com/platforms/email) - [Sporetag for SMS](https://sporetag.com/platforms/sms) ## Walkthroughs Demo walkthroughs on a made-up shop. Every number in them is demo data. - [Demo walkthroughs](https://sporetag.com/walkthroughs) - [Walkthrough: Three ad sets looked equal. One made the sales.](https://sporetag.com/walkthroughs/ad-sets) - [Walkthrough: The bio link that sold more than the ads.](https://sporetag.com/walkthroughs/bio-link) - [Walkthrough: Which email actually paid.](https://sporetag.com/walkthroughs/email) ## Tools - [Free tools](https://sporetag.com/tools) - [Free tag checker: which analytics and ad tags a site loads](https://sporetag.com/tools/tag-checker) - [Free UTM builder](https://sporetag.com/tools/utm-builder) - [Ad blocker estimator: visitors your analytics may miss](https://sporetag.com/tools/ad-blocker-estimator) ## Compare - [Comparisons](https://sporetag.com/vs) - [Sporetag vs Google Analytics](https://sporetag.com/vs/google-analytics) - [Sporetag vs Hyros](https://sporetag.com/vs/hyros) - [Sporetag vs Triple Whale](https://sporetag.com/vs/triple-whale) - [Sporetag vs Northbeam](https://sporetag.com/vs/northbeam) - [Sporetag vs Wicked Reports](https://sporetag.com/vs/wicked-reports) - [Sporetag vs Cometly](https://sporetag.com/vs/cometly) - [Sporetag vs Plausible](https://sporetag.com/vs/plausible) - [Sporetag vs Fathom](https://sporetag.com/vs/fathom) - [Sporetag vs Umami](https://sporetag.com/vs/umami) - [Sporetag vs Simple Analytics](https://sporetag.com/vs/simple-analytics) - [Sporetag vs Matomo](https://sporetag.com/vs/matomo) - [Sporetag vs Dub](https://sporetag.com/vs/dub) - [Sporetag vs Bitly](https://sporetag.com/vs/bitly) - [Sporetag vs Rebrandly](https://sporetag.com/vs/rebrandly) - [Sporetag vs Short.io](https://sporetag.com/vs/short-io) - [Sporetag vs AgencyAnalytics](https://sporetag.com/vs/agencyanalytics) ## Company - [Agency partners: agencies that set up Sporetag for clients](https://sporetag.com/partners) - [Security](https://sporetag.com/security) - [Data, retention and backups](https://sporetag.com/data) - [Status](https://sporetag.com/status) - [Privacy policy](https://sporetag.com/privacy) - [Terms of service](https://sporetag.com/terms) ## Optional - [Full text of the docs, guides and glossary](https://sporetag.com/llms-full.txt): every page below and above as Markdown, in one file - [Analytics glossary](https://sporetag.com/glossary.md) - [Ad blocker](https://sporetag.com/glossary/ad-blocker.md): Browser software that blocks ads and, often, the tracking scripts and pixels that measure them. - [ARR](https://sporetag.com/glossary/arr.md): Annual recurring revenue: the yearly run rate of active subscriptions, usually MRR × 12. - [Attribution](https://sporetag.com/glossary/attribution.md): The rule that decides which marketing touch gets credit for a sale, signup or other conversion. - [Attribution window](https://sporetag.com/glossary/attribution-window.md): How long after a click or view a conversion can still be credited to it. - [Blended ROAS](https://sporetag.com/glossary/blended-roas.md): Total revenue from your store divided by total ad spend on every platform, for the same period. - [Bot traffic](https://sporetag.com/glossary/bot-traffic.md): Visits made by automated software rather than people: crawlers, scrapers, monitors and fake clicks. - [Bounce rate](https://sporetag.com/glossary/bounce-rate.md): The share of visits or sessions that ended without engagement; each tool defines it differently. - [Break-even ROAS](https://sporetag.com/glossary/break-even-roas.md): The ROAS at which ad revenue exactly covers the ad spend and the cost of the goods sold: 1 ÷ gross margin. - [Call tracking](https://sporetag.com/glossary/call-tracking.md): Crediting phone calls to their source by giving each ad, place or website visitor its own forwarding number. - [Churn](https://sporetag.com/glossary/churn.md): The share of paying customers, or of recurring revenue, that stops in a period. - [Click ID](https://sporetag.com/glossary/click-id.md): A unique value an ad platform adds to the link when someone clicks an ad, so it can match later conversions to that click. - [Consent banner](https://sporetag.com/glossary/consent-banner.md): The notice that asks visitors to accept or decline cookies and similar tracking on a website. - [Consent mode](https://sporetag.com/glossary/consent-mode.md): Google's way for its tags to change behavior based on the visitor's consent choices. - [Conversion](https://sporetag.com/glossary/conversion.md): An action you count as success: a purchase, a signup, a booked call, a form sent. - [Conversion rate](https://sporetag.com/glossary/conversion-rate.md): The share of visits, sessions or users that converted. - [Conversion window](https://sporetag.com/glossary/conversion-window.md): The Google Ads setting for how long after an ad interaction a conversion can be recorded. - [Conversions API](https://sporetag.com/glossary/conversions-api.md): Meta's server-to-server interface for sending conversion events, alongside or instead of the pixel. - [Cookieless tracking](https://sporetag.com/glossary/cookieless-tracking.md): Measuring visits without storing cookies or other data on the visitor's device. - [Cost per lead](https://sporetag.com/glossary/cost-per-lead.md): Ad spend divided by the number of leads it brought, for the same period and campaigns. - [CPA](https://sporetag.com/glossary/cpa.md): Cost per acquisition: ad spend divided by the number of conversions. - [Dark social](https://sporetag.com/glossary/dark-social.md): Shares through private channels, such as messaging apps and email, that arrive without a referrer. - [Data thresholds](https://sporetag.com/glossary/data-thresholds.md): GA4 rules that withhold small rows of data so individual users cannot be identified. - [Data-driven attribution](https://sporetag.com/glossary/data-driven-attribution.md): A model that learns how to split credit from your own conversion paths, instead of a fixed rule. - [Direct traffic](https://sporetag.com/glossary/direct-traffic.md): Visits that arrived with no referrer, no campaign tags and no click id, so the tool cannot tell where they came from. - [Dynamic number insertion](https://sporetag.com/glossary/dni.md): A script that shows each website visitor their own tracking number, so a call can be tied to the visit. - [Engagement rate](https://sporetag.com/glossary/engagement-rate.md): In GA4, the share of sessions that were engaged. - [Enhanced conversions](https://sporetag.com/glossary/enhanced-conversions.md): Google Ads' feature that sends hashed customer details with conversions to improve matching. - [Event deduplication](https://sporetag.com/glossary/event-deduplication.md): Merging the same conversion reported twice, such as by the browser and the server, so it counts once. - [Event Match Quality](https://sporetag.com/glossary/event-match-quality.md): Meta's score for how well the customer details on your server events can be matched to Meta accounts. - [Exit rate](https://sporetag.com/glossary/exit-rate.md): The share of a page's views that were the last in their visit. - [fbclid](https://sporetag.com/glossary/fbclid.md): Meta's click id, added to links people click on Facebook and Instagram. - [First-party cookie](https://sporetag.com/glossary/first-party-cookie.md): A cookie set by the site the visitor is on, readable only by that site. - [First-touch attribution](https://sporetag.com/glossary/first-touch-attribution.md): A model that gives all the credit for a conversion to the first known touch. - [gclid](https://sporetag.com/glossary/gclid.md): Google Ads' click id, added to landing page links by auto-tagging. - [Global Privacy Control](https://sporetag.com/glossary/global-privacy-control.md): A browser signal asking websites not to sell or share the visitor's personal data. - [Incrementality](https://sporetag.com/glossary/incrementality.md): The conversions an ad caused that would not have happened without it. - [Intelligent Tracking Prevention](https://sporetag.com/glossary/itp.md): Safari's set of limits on cookies and storage used for tracking. - [Key event](https://sporetag.com/glossary/key-event.md): GA4's name for an event you mark as important to your business, such as a purchase, a signup or a booked call. - [Landing page](https://sporetag.com/glossary/landing-page.md): The first page a visitor sees in a visit, or a page built for one campaign. - [Landing page experience](https://sporetag.com/glossary/landing-page-experience.md): Google Ads' estimate of how relevant and useful a landing page is for the people who click an ad. - [Last-touch attribution](https://sporetag.com/glossary/last-touch-attribution.md): A model that gives all the credit for a conversion to the final touch before it. - [Lifetime value](https://sporetag.com/glossary/ltv.md): The total revenue, or profit, a customer brings over their whole relationship with you. - [Lift test](https://sporetag.com/glossary/lift-test.md): An experiment that compares people who saw ads with a held-back group to measure the ads' real effect. - [Marketing mix model](https://sporetag.com/glossary/marketing-mix-model.md): A statistical model that estimates each channel's effect on sales from aggregate spend and sales over time. - [MER](https://sporetag.com/glossary/mer.md): Marketing efficiency ratio: total revenue divided by total marketing spend. - [MRR](https://sporetag.com/glossary/mrr.md): Monthly recurring revenue: the monthly value of every subscription that is paying now. - [Multi-touch attribution](https://sporetag.com/glossary/multi-touch-attribution.md): Any attribution model that splits credit across more than one touch. - [Pageview](https://sporetag.com/glossary/pageview.md): One page loaded and counted by an analytics tool. - [QR code](https://sporetag.com/glossary/qr-code.md): A square barcode that phones read with the camera to open a link. - [Referrer](https://sporetag.com/glossary/referrer.md): The address of the page a visitor came from, sent by the browser when they follow a link. - [Retention rate](https://sporetag.com/glossary/retention-rate.md): The share of customers, or of recurring revenue, still with you at the end of a period. - [ROAS](https://sporetag.com/glossary/roas.md): Return on ad spend: revenue credited to ads divided by what the ads cost. - [Sampling](https://sporetag.com/glossary/sampling.md): Building a report from a portion of the data and scaling the result up to estimate the whole. - [Server-side tagging](https://sporetag.com/glossary/server-side-tagging.md): Running marketing and analytics tags on a server you control, which then forwards data to each vendor. - [Server-side tracking](https://sporetag.com/glossary/server-side-tracking.md): Sending analytics or conversion events from a server, rather than from the visitor's browser. - [Session](https://sporetag.com/glossary/session.md): A group of pageviews and events from one browser, ended by a period of inactivity or another rule. - [Session timeout](https://sporetag.com/glossary/session-timeout.md): How long a visitor can be inactive before their session ends and the next action starts a new one. - [Short link](https://sporetag.com/glossary/short-link.md): A short address on a link domain that redirects to a longer one, counting the click on the way. - [Third-party cookie](https://sporetag.com/glossary/third-party-cookie.md): A cookie set by a domain other than the one in the address bar, used to follow people across sites. - [Unique visitor](https://sporetag.com/glossary/unique-visitor.md): A browser or person counted once in a period, however many times they visited. - [UTM parameters](https://sporetag.com/glossary/utm-parameters.md): Tags added to the end of a link that tell analytics tools the source, medium and campaign of the visit. - [utm_campaign](https://sporetag.com/glossary/utm-campaign.md): The UTM parameter that names the specific push, offer or promotion a link belongs to. - [utm_content](https://sporetag.com/glossary/utm-content.md): The UTM parameter that tells apart links or creatives within the same campaign. - [utm_medium](https://sporetag.com/glossary/utm-medium.md): The UTM parameter that names the kind of channel: social, cpc, email, sms, qr. - [utm_source](https://sporetag.com/glossary/utm-source.md): The UTM parameter that names who sent the visit: a site, app, newsletter or partner. - [utm_term](https://sporetag.com/glossary/utm-term.md): The UTM parameter originally made for the paid search keyword, often used for the ad set or audience. - [View-through conversion](https://sporetag.com/glossary/view-through-conversion.md): A conversion credited to an ad the person saw but did not click. - [Year over year](https://sporetag.com/glossary/year-over-year.md): A comparison of a period with the same period a year earlier, to see growth after seasonality. --- # Getting started > Create an account, add your first site, paste one script tag and see your first visit in Sporetag. Then make your first short link. Source: https://sporetag.com/docs/getting-started Section: Start here Sporetag counts visits to your website and clicks on your short links. It shows both in one dashboard, so you can follow a click from Instagram to the visit, then to the signup or sale. This page takes you from a new account to your first visit. It takes about five minutes. ## 1. Create an account Go to [Sign up](https://sporetag.com/signup) and enter your email and a password. We send you a link to confirm your email. You can look around before you confirm, but you need a confirmed email to make short links. ## 2. Add a site In the dashboard, choose **Add site** and enter the domain, for example `shop.example.com`. Leave out `https://` and `www.`. Subdomains of the domain you enter are counted too. The Free plan has 1 site. Solo has 5, Studio has 25 and Agency has 100. See [Billing and limits](https://sporetag.com/docs/billing-and-limits). ## 3. Add the script Paste this tag into the `` of every page. Use your own domain in `data-site`. ```html ``` Most site builders have a box for code in the head. [Add the script](https://sporetag.com/docs/add-the-script) has steps for common ones. ## 4. Check that it works Open your site in a normal browser tab and stay on the page for a few seconds. The script waits until the tab has been visible for 1.5 seconds before it counts a visit. That keeps out tabs that open in the background and close again. Then open the site in your dashboard. The **Live** count shows visitors from the last five minutes. The dashboard is built for your kind of site and fills in as you connect ads or a store. Click any number to see what makes it. See [Dashboards](https://sporetag.com/docs/dashboards). > If nothing shows up, check that the domain in `data-site` matches the site you added, and that an ad blocker is not stopping the script. A [script proxy](https://sporetag.com/docs/script-proxy), on paid plans, gets past most blockers. ### Pick the dates The button over the dashboard holds the period and what it is compared with. Every card follows it. **Previous period** compares like for like: this month so far, October 1 to 23, against September 1 to 23. **Same period last year** uses the same dates a year back. Turn on **Match weekdays** to go back 364 days instead, so a Monday lines up with a Monday. **No comparison** hides every change. Keys: **T** today, **W** last 7 days, **M** last 30 days, **X** comparison on or off, **Left** and **Right** step back and forward one period. The address keeps the period and the comparison, so a copied link or a dashboard's share link opens the same view. ## 5. Make a short link Open **Links** and choose **New link**. Paste a long address, pick where you will share it, such as SMS or Instagram bio, and choose **Make link**. You get a link like `go.sporetag.com/a8Kd2Q`, ready to copy. If the link points to a site you track, Sporetag ties the click to the visit that follows. See [Short links](https://sporetag.com/docs/short-links). ## 6. Use your own domain On a paid plan, put your links on `go.yourdomain.com` instead. People, Meta, Instagram and email filters trust your own name more. It takes one DNS record. See [Custom short domains](https://sporetag.com/docs/custom-short-domains). ## Next steps The Events API, the Meta Conversions API, the script proxy and attribution are on paid plans: Solo, Studio, Agency and Custom. - Count signups and sales with [custom events and goals](https://sporetag.com/docs/custom-events-and-goals). - Send sales from your server with the [Events API](https://sporetag.com/docs/events-api). - Send conversions to Meta with the [Meta Conversions API](https://sporetag.com/docs/meta-conversions-api). - Pick a [tracking mode](https://sporetag.com/docs/tracking-modes) for each site. --- # Dashboards > Boards built for your site, a breakdown behind every number, cards that say why they are empty, monthly targets, and edits that save themselves. Source: https://sporetag.com/docs/dashboards Section: Start here Each site opens on its dashboard: a board of cards, each one a number, a chart or a table. Every card follows the period and the comparison at the top (see [Pick the dates](https://sporetag.com/docs/getting-started#pick-the-dates)). ## Boards built for you Sporetag builds the first board from the kind of site and what you have connected. Until you change its cards, it keeps itself current: connect Meta or Stripe and the cards for them appear on their own. Click the dashboard's name to switch boards. **New dashboard** starts one from a board for your business: | Board | What it holds | |---|---| | Overview | Picked for this site from what you connect | | Store | Revenue, orders, return on ads, the funnel | | Lead gen | Leads, cost per lead and where they come from | | SaaS | Signups, MRR and lifetime value by source | | Local service | Calls, form leads and cost per lead | | Content | Readers, top pages and newsletter signups | | Agency client | Three numbers and the goal, for a client | | Blank | Start empty and add cards | The same menu has **Duplicate**, **Rename**, **Earlier versions** and **Set as default**. Each person can have 1 board per site on Free, 5 on Solo, 12 on Studio and 25 on Agency. ## See what makes a number Click a number, an ad tile or a point on a chart to open its breakdown. It slides in from the right, or up from the bottom on a phone. It shows the number for the period, or for the day you clicked, split up to four ways: - Visits: **Source**, **Campaign**, **Page** and **Device**. - Ads: **Platform**, **Campaign**, **Ad set** and **Ad**. A split the card is already filtered on is left out. The foot of the breakdown has one link that goes deeper: - **See these visitors** opens Profiles with the people seen in that span, on sites with [90-day tracking](https://sporetag.com/docs/tracking-modes). - **Open in Attribution** opens the ads on the [Attribution report](https://sporetag.com/docs/attribution-report). - **Add a note** writes a [note](https://sporetag.com/docs/chart-notes) on that day, from a day on the main chart. Press Escape or click outside to close it. ## When a card has no numbers A card with nothing to show says why in one line, with one button to fix it: | The card says | The button | |---|---| | No ad account connected yet. | **Connect your ads**, or the platform the card is about, such as **Connect Meta Ads** | | No store connected yet. | **Connect your store**, or the store the card is about, such as **Connect Shopify** | | No email tool connected yet. | **Connect your email tool**, or the tool the card is about, such as **Connect Klaviyo** | | Stripe is not connected yet. | **Connect Stripe** | | No tracking number yet. | **Set up call tracking** | | Pick what counts as a lead. | **Add a goal** | | No visitors in this range, or the card's own number, such as No signups in this range. | **Try last 30 days**, when the range is shorter than 4 weeks | | Tracking started Oct 12. | **Show from Oct 12**, when the whole range is before the first visit | | On Solo, Studio and Agency. | **See plans**, or a free trial if you never had a paid plan | | This card could not load. | **Try again** | Days before the first tracked visit show as no data, not zero. Charts start their visit lines on that day, and the main chart gets a **Tracking started** note, unless you [imported history](https://sporetag.com/docs/import-history) from before it. ### When numbers are late A card whose numbers come from a connected tool says so when they are older than they should be: - **Meta synced 9 h ago**: an ad platform that has not synced for 4 hours, or a store or email tool for 1 hour. - **Meta stopped Oct 21.** with **Reconnect**: the connection broke. The card keeps the numbers it had. ### Filters that cannot apply Filters at the top narrow visits. Ad spend, sales, email and calls have no visitor source, so those cards are grayed out and say **Not filtered**. A UTM campaign filter on its own does narrow ad numbers to that campaign. ## What the card sentences mean When a comparison is picked at the top, a number card with **Compare to previous period** on can add one sentence that names what moved it, such as "Signups up 22%, mostly from Meta (+31)". A one-row card shows only the second half: "Mostly from Meta (+31)". A sentence shows only when all of these are true: - The period before had at least 10. - The change is 15% or more, and at least 5. - One source or platform made at least half of the change, and at least 5 of it. When the change is spread thin, there is no sentence. The card's percent already says it. In the [simple view](https://sporetag.com/docs/autopilot#the-simple-view-for-clients), up to two of these sentences from the number cards clients see follow the summary. ### The unusual dot When a number moved far from a usual day for that weekday, its number card gets a dot in the header, and on a card half the board wide or more, the words "Unusual for a Tuesday". Point at it to read what changed and its likely cause. Click it to open the change on **Alerts**. It shows on visitors, your goal's conversions and conversion rate, revenue, ad spend and cost per result. See [Unusual changes](https://sporetag.com/docs/autopilot#unusual-changes). ## Monthly targets Give a number card a target and it shows where you stand this month. 1. Open the card's menu and choose **Edit this widget**. 2. Under **More**, type a number in **Monthly target**. Clear it to remove the target. The card grows to two rows for a bar, a mark for where it should be by today, and one line: - For a total, such as visitors, signups, revenue or spend: "236 of 500 this month", then "Needs 18 a day, getting 15" or "On pace for 520". Once the site has 4 weeks of data, pace is weighted by its busy and quiet weekdays over the last 8 weeks, so a quiet Monday does not read as behind. - For a rate or a cost per one, such as conversion rate or cost per lead, there is no pace. The month so far is held against the target: "$22 this month" and "Target $25 or less". The status reads **On track** at the target's pace or better, **Close** at 90% to 99% of it, and **Behind** under 90%. A number where lower is better, like a cost per lead, reads **Over** instead of Behind. Nothing is judged in the first 2 days of the month. A total that reaches its target reads **Hit** and **Target reached**. On day 10 and day 20 of the month, a target that is Behind or Over sends the **A target falls behind** alert, once per target per month. Turn it off in **Alerts**, under the site's **Alert settings**. Targets on the dashboard your clients see also show in the simple view and in [client report](https://sporetag.com/docs/client-reports) emails. ## Change a dashboard There is no Save button. Every change saves itself about a second after you make it. - **Add card** opens one sheet: **Suggested** cards picked from your own numbers, each with why; **Search every card**; and **Or start a new dashboard**. A card you pick lands where you are looking. You do not need to press **Edit** first. A dashboard holds 24 cards. - **Edit** lets you move cards and change them. Drag a card by its header, or select one and use the arrow keys. A card's menu has **Chart settings**, **Duplicate**, **Move up**, **Move down** and **Remove**. In **Chart settings**, pick the **Metric**, **Show as** (Number, Line, Bar or Table) and **Split by**. Title, filters (up to 3), goal, compare, target and size are under **More**. - On a phone or tablet, press **Arrange** while editing to move cards up or down, or remove them, from a list. - The bar says **Saving**, then **Saved**. Press **Done** when you are finished. ### Undo and earlier versions **Undo** and **Redo** go back and forward up to 50 steps while the page is open, in or out of editing. Cmd+Z or Ctrl+Z undoes. Add Shift, or press Ctrl+Y, to redo. Adding a card, removing one, **Reset** and **Restore** each show a message with **Undo**, so none of them asks first. **Earlier versions**, in the menu under the dashboard's name, keeps the last 20 versions of the board, each with its time and number of cards. A burst of quick changes is one version: a new one is kept only when the board had stood for 5 minutes, and before every Reset and Restore. Press **Restore** next to a version to bring it back. ### If a change does not save - **This dashboard changed in another tab. Reload to see it.** Another tab saved first. This tab stops saving, so it never wipes that change. Press **Reload**. - **Not saved. Check your connection.** Press **Try again** once you are back online. The change waits until then. Closing the tab sends any change still waiting. Shared links, client logins and the demo never save changes. --- # Assistant > Ask the assistant for goals, dashboards, links, segments, flows, client reports, emails and texts. Every change waits for your OK. Source: https://sporetag.com/docs/assistant Section: Start here Sporetag Assistant sets things up for you when you ask in plain words. It reads your stats and settings, then proposes each change on a card. Nothing changes until you press **Apply**. If the assistant reads "(when shipped)" in the app, it is not switched on for Sporetag yet. ## Open it Press **Assistant** at the top of any page in the app. On a computer it opens on the right. On a phone it slides up from the bottom. It knows which site and page you are on, and keeps one conversation per site. **New chat** (the plus) starts over. Not sure what to ask? Each page shows a few ideas, like: - Set up my goals - Build me a signups dashboard - Set up an abandoned checkout flow - Write and schedule a welcome series - Make a weekly ads report for my client ## What it can do | Ask for | What happens | |---|---| | Stats and results | It reads your dashboard and the Attribution report, then answers. | | Goals | It proposes a goal, like "Someone buys" or a thank-you page. | | A dashboard | It makes a new named dashboard from a template (Store, Lead gen, SaaS, Local service, Content, Agency client), changes the charts and tables on any of your dashboards, or sets which goal a dashboard counts. | | Short links | It proposes a link with the right UTM tags, like `instagram` and `bio`. | | Segments | It proposes a group of customers by source, orders or spend. | | Setup help | It checks your tag and integrations and says what is wrong, with the steps from these guides. | | Emails and texts | It reads your website for your brand voice, then drafts a subject, preview text and body, or a text message. | | Automations | It builds [flows](https://sporetag.com/docs/automations): an abandoned checkout reminder, a welcome series, or any trigger and steps you describe. It adds emails and texts to a flow, pauses and resumes flows, and sends you a test. | | Client reports | It makes a [client report](https://sporetag.com/docs/client-reports) from a template, sets when it goes and who gets it, changes it, and sends you a test. | ## Flows send to real people A flow the assistant builds is saved as a draft in **Automations**. Nothing goes to a customer until you publish it. The **Publish** card says what it will send and to whom, and asks you to apply only if those people gave you their details to hear from you. **Undo** on it pauses the flow. - Emails come from Sporetag's sending address with your site's name, your postal address and an unsubscribe link. Sending from your own domain is (when shipped). - Texts go only to people who agreed to texts, never at night their time, and each part costs money. Cards with texts say so. Texts are (when shipped). - Tests go to you only: a test email to your sign-in address, a test text to the number you type on the card. Reports work the same way: the card says when the report will email your clients. Add their addresses on the card with **Edit**; the assistant never asks for them in chat. ## Apply, Edit, Cancel Every change shows as a card first: what will be created or changed, on which site. - **Apply** makes the change. - **Edit** lets you change the name, address or wording first, then Apply. - **Cancel** leaves everything as it was. If you type a new message instead, any open card is canceled. The **Changes** tab lists what you applied, newest first. Most changes have **Undo**: a goal is removed, a dashboard goes back to how it was or a new one is deleted, a short link is archived, a segment or draft is deleted, a new flow or report is deleted, an added step comes out again, and a published flow is paused. Test sends cannot be undone. ## Drafts Emails and texts are saved as drafts in the **Drafts** tab once you press Apply. Press **Use in a flow** and the assistant proposes a flow card with it, to send it from Sporetag. Or copy the subject or the whole email into your email tool: pick **For Klaviyo** or **For Mailchimp** and the merge fields are written the way that tool expects. In a flow, `{{first_name}}` becomes the flow's first name field (with "there" when it is not known) and both source fields become where they came from. Flows add the unsubscribe link themselves. Orders and lifetime spend cannot go in a flow yet. Drafts can use these merge fields: | Field | What it is | |---|---| | `{{first_name}}` | The person's first name | | `{{sporetag_first_source}}` | Where they first came from | | `{{sporetag_last_source}}` | Where they came from most recently | | `{{sporetag_orders}}` | How many orders they made | | `{{sporetag_ltv}}` | What they spent in total | | `{{unsubscribe_link}}` | The unsubscribe link (emails only) | The `sporetag_` fields are filled in by your email tool from the details Sporetag sends it. See [Segments and best send time](https://sporetag.com/docs/segments-and-best-send-time). ## Clients People you invite to a site's dashboard can open the assistant too. By default they can only ask questions. To let them add goals, segments and drafts (still only after they press Apply), open the assistant on that site, go to **Changes**, and turn on **Invited clients can make changes**. Short links and dashboard layouts stay with you. Their messages count toward your plan. ## AI actions per month Each message you type is one AI action. So is each weekly plan made for a site. Your plan includes some every month, from the 1st: | Plan | AI actions a month | |---|---| | Free | 20 | | Solo | 200 | | Studio | 1,000 | | Agency | 3,000 | | Custom | 10,000 | Applying or canceling a card does not count again. **Billing** shows how many you used and when they reset. We email you once at 80% and once when they are all used. **Past your plan.** On a paid plan you can keep going. Each extra action is a small usage charge, shown in the **Past your plan** line on **Billing**, with texts and emails. Billing says whether it is billed yet: until usage billing starts, it is not. Your **usage limit** (set on Billing, $25 to start) caps it: at the limit, extra actions pause until the 1st, and we tell you. Set it to 0 to stop at what your plan includes. Free stops at its 20 a month. To keep things fair, one person can send 20 messages in 10 minutes and 150 a day. ## What the assistant sees Sporetag Assistant runs on an open model hosted by Cloudflare Workers AI, inside the same Cloudflare account that hosts Sporetag. Anthropic is not used today. The [privacy policy](https://sporetag.com/privacy) lists who processes what. To answer, Sporetag sends the model your question, the page you are on, and what the tools read: stats and report summaries, goal and segment names, counts of customers and visitors, and text from your public website. It never sends contact details (emails, phone numbers or names of your customers) or passwords and keys. Text from websites and customer data is marked as outside data, and the assistant is told never to follow instructions in it. Even if it were fooled, it could only propose a change. Nothing happens until you press Apply, and a card shows a warning when it was suggested after reading your website or customer data. --- # Add the script > Paste the Sporetag script tag into your site's head. Steps for plain HTML, WordPress, Shopify, Webflow, Squarespace, Wix and single page apps. Source: https://sporetag.com/docs/add-the-script Section: Start here The script is one tag. In Private mode, the default, it sets no cookies and stores nothing in the browser. ```html ``` Put it in the `` of every page. `data-site` is the domain you added in Sporetag. ## What the script does - Counts a pageview once the tab has been visible for 1.5 seconds. - Sends how long the page was visible when the visitor leaves. - Follows page changes in single page apps that use the History API. - Reads UTM tags and ad click ids (`gclid`, `gbraid`, `wbraid`, `fbclid`) from the landing address. - Does nothing in automated browsers that report `navigator.webdriver`. Step-by-step guides: [Shopify](https://sporetag.com/docs/install-shopify), [WordPress](https://sporetag.com/docs/install-wordpress), [Squarespace](https://sporetag.com/docs/install-squarespace), [Wix](https://sporetag.com/docs/install-wix), [Webflow](https://sporetag.com/docs/install-webflow), [Framer](https://sporetag.com/docs/install-framer), [Google Tag Manager](https://sporetag.com/docs/install-google-tag-manager) and [any other site](https://sporetag.com/docs/install-html). ## Plain HTML Paste the tag inside `` on each page, or in your shared header template. ## WordPress Use your theme's header settings, or a plugin that adds code to the head. Paste the tag as it is. Clear any page cache after you save. ## Shopify In the admin, open **Online Store**. Next to your theme, click **...**, then **Edit code**. Open `theme.liquid` and paste the tag just before ``. [Full Shopify guide](https://sporetag.com/docs/install-shopify). ## Webflow, Squarespace and Wix Each has a site wide setting for custom code in the head. Paste the tag there and publish the site. Some of these builders only allow custom code on paid plans. ## Single page apps Load the tag once, in the main HTML file. The script listens for route changes and counts each one as a pageview. You do not need to call anything yourself. ## Check it Open your site, wait a few seconds, then look at the **Live** count in your dashboard. The same browser counts as one visitor per day. ## Ad blockers Some blockers stop analytics scripts by their address. To count those visits, serve the script from your own domain with a [script proxy](https://sporetag.com/docs/script-proxy). --- # Install on Shopify > Add Sporetag to your Shopify store in about five minutes. Copy one line and paste it into your theme. No coding needed. Source: https://sporetag.com/docs/install-shopify Section: Start here You copy one line from Sporetag and paste it into your Shopify theme. It takes about five minutes. ## Before you start Copy your tag. In Sporetag, open [Set up your site](https://sporetag.com/app/start), or open your site's **Settings**. Your tag looks like this, with your own address: ```html ``` ## Steps 1. In your Shopify admin, open **Online Store**. You land on your themes. 2. Next to your current theme, click the **...** button, then **Edit code**. 3. In the **layout** folder, open `theme.liquid`. 4. Find the line ``. Paste the tag on the line just above it. 5. Click **Save**. ## Check it works Go back to Sporetag. On the last setup step, click **Check my site**. Then open your store in a new tab. Your first visit shows up in a minute or two. ## Good to know - Shopify checkout pages do not run theme code, so the tag does not see them. To count sales, connect your store with the [Shopify connector](https://sporetag.com/docs/shopify-connector), on paid plans. Each order then shows with the ad or link that brought it, and every buyer and new customer account is added to [Profiles](https://sporetag.com/docs/customer-profiles) with their email. No extra code. - If you switch to a new theme later, paste the tag into the new theme too. - A store with a password page still works, but our check cannot see past the password. Open the store yourself and wait for the first visit. --- # Install on WordPress > Add Sporetag to a WordPress site with the free WPCode plugin. Copy one line, paste it in the header box, and save. No coding needed. Source: https://sporetag.com/docs/install-wordpress Section: Start here You add a small free plugin, then paste one line from Sporetag. It takes about five minutes. ## Before you start Copy your tag. In Sporetag, open [Set up your site](https://sporetag.com/app/start), or open your site's **Settings**. Your tag looks like this, with your own address: ```html ``` ## Steps 1. In your WordPress admin, go to **Plugins**, then **Add New Plugin**. 2. Search for **WPCode**. Click **Install Now**, then **Activate**. 3. Go to **Code Snippets**, then **Header & Footer**. 4. Paste the tag into the **Header** box and save. 5. If you use a cache plugin, clear its cache. ## Check it works Go back to Sporetag. On the last setup step, click **Check my site**. Then open your site in a new tab. Your first visit shows up in a minute or two. ## Good to know - Any plugin that adds code to the head works the same way. Some themes have a header code box in their own settings too. - On WordPress.com, adding plugins may need a paid plan. - If the check says the tag is missing, clear your cache plugin and any CDN cache, then check again. --- # Install on Squarespace > Add Sporetag to a Squarespace site with Code Injection. Copy one line, paste it into the Header box, and save. No coding needed. Source: https://sporetag.com/docs/install-squarespace Section: Start here You paste one line from Sporetag into Squarespace's Code Injection panel. It takes about three minutes. ## Before you start Copy your tag. In Sporetag, open [Set up your site](https://sporetag.com/app/start), or open your site's **Settings**. Your tag looks like this, with your own address: ```html ``` ## Steps 1. Open the **Code Injection** panel. In most sites it is under **Pages**, then **Website Tools**. 2. Paste the tag into the **Header** box. 3. Click **Save**. ## Check it works Go back to Sporetag. On the last setup step, click **Check my site**. Then open your site in a new tab. Your first visit shows up in a minute or two. ## Good to know - Squarespace offers Code Injection on its Core, Plus and Advanced plans. - Squarespace checkout pages do not run injected code, so Sporetag does not count them. - A site with a password or that is not published yet cannot be checked from outside. Open it yourself and wait for the first visit. --- # Install on Wix > Add Sporetag to a Wix site with Custom Code in your site settings. Paste one line, place it in the head of all pages, and apply. Source: https://sporetag.com/docs/install-wix Section: Start here You paste one line from Sporetag into Wix's Custom Code settings. It takes about five minutes. ## Before you start Copy your tag. In Sporetag, open [Set up your site](https://sporetag.com/app/start), or open your site's **Settings**. Your tag looks like this, with your own address: ```html ``` ## Steps 1. In your site dashboard, open **Settings**. 2. Under **Development & integrations**, click **Custom Code**. 3. Click **+ Add Custom Code** and paste the tag. Name it Sporetag. 4. Under **Add Code to Pages**, pick **All pages**, and load the code on each new page. 5. Under **Place Code in**, pick **Head**. Click **Apply**. ## Check it works Go back to Sporetag. On the last setup step, click **Check my site**. Then open your site in a new tab. Your first visit shows up in a minute or two. ## Good to know - Wix runs custom code only on a published site with a connected domain. - Add the site to Sporetag with that domain, like yoursite.com, not the Wix editor address. --- # Install on Webflow > Add Sporetag to a Webflow site. Paste one line into the Head code box in Site settings, save, then publish. No coding needed. Source: https://sporetag.com/docs/install-webflow Section: Start here You paste one line from Sporetag into Webflow's site settings, then publish. It takes about three minutes. ## Before you start Copy your tag. In Sporetag, open [Set up your site](https://sporetag.com/app/start), or open your site's **Settings**. Your tag looks like this, with your own address: ```html ``` ## Steps 1. Open your site's **Site settings**. 2. Click **Custom code**. 3. Paste the tag into the **Head code** box. Click **Save**. 4. Publish your site. The tag runs only after you publish. ## Check it works Go back to Sporetag. On the last setup step, click **Check my site**. Then open your site in a new tab. Your first visit shows up in a minute or two. ## Good to know - Webflow may ask you to add a site plan before you can use custom code. - Code in **Head code** runs on every page. You do not need to add it page by page. --- # Install on Framer > Add Sporetag to a Framer site. Paste one line into the Custom Code section of Site Settings, then publish. No coding needed. Source: https://sporetag.com/docs/install-framer Section: Start here You paste one line from Sporetag into Framer's site settings, then publish. It takes about three minutes. ## Before you start Copy your tag. In Sporetag, open [Set up your site](https://sporetag.com/app/start), or open your site's **Settings**. Your tag looks like this, with your own address: ```html ``` ## Steps 1. Open your project's **Site Settings**. 2. Find the **Custom Code** section. 3. Paste the tag into the box for the start of the head tag. 4. Publish your site. ## Check it works Custom code does not run in the Framer preview, only on the published site. Go back to Sporetag. On the last setup step, click **Check my site**. Then open your published site in a new tab. Your first visit shows up in a minute or two. ## Good to know - Code in Site Settings runs on every page. Page settings can add more, but you do not need them for Sporetag. --- # Install with Google Tag Manager > Add Sporetag through Google Tag Manager with a Custom HTML tag on all pages. Use this if Tag Manager is already on your site. Source: https://sporetag.com/docs/install-google-tag-manager Section: Start here If Google Tag Manager is already on your site, you can add Sporetag there. It takes about five minutes. ## Before you start Copy your tag. In Sporetag, open [Set up your site](https://sporetag.com/app/start), or open your site's **Settings**. Your tag looks like this, with your own address: ```html ``` ## Steps 1. In Tag Manager, open your container. Click **Tags**, then **New**. 2. Name it Sporetag. Click **Tag Configuration** and pick **Custom HTML**. 3. Paste the tag into the **HTML** box. 4. Under **Triggering**, pick **Initialization - All Pages**. Click **Save**. 5. Click **Submit**, then **Publish**. ## Check it works Tag Manager adds tags after the page loads, so the **Check my site** button cannot see them. Open your site in a new tab instead. On the last setup step in Sporetag, your first visit shows up in a minute or two. ## Good to know - Nothing is counted until you publish the container. - If your site has no Tag Manager yet, it is simpler to paste the tag straight into your site. See [Install on any site](https://sporetag.com/docs/install-html). --- # Install on any site > Add Sporetag to any website. Paste one line into the head of every page, or into the head code setting your site builder has. Source: https://sporetag.com/docs/install-html Section: Start here Every website can run Sporetag. You paste one line into the `` of each page. ## Before you start Copy your tag. In Sporetag, open [Set up your site](https://sporetag.com/app/start), or open your site's **Settings**. Your tag looks like this, with your own address: ```html ``` ## Steps 1. Open the HTML of each page, or the header file all pages share. 2. Paste the tag just above ``. 3. Save, then upload or publish the change. ## Using a site builder? Most builders have a setting called head code, header code, custom code or code injection. Paste the tag there. It then runs on every page. We have step-by-step guides for [Shopify](https://sporetag.com/docs/install-shopify), [WordPress](https://sporetag.com/docs/install-wordpress), [Squarespace](https://sporetag.com/docs/install-squarespace), [Wix](https://sporetag.com/docs/install-wix), [Webflow](https://sporetag.com/docs/install-webflow), [Framer](https://sporetag.com/docs/install-framer) and [Google Tag Manager](https://sporetag.com/docs/install-google-tag-manager). ## What the one line does On paid plans, a new site starts with 90-day tracking, and the tag in setup loads `sa.js` instead of `s.js`. That one line then does three things, with no second step: - **Visits.** Every page view, with where the visitor came from. - **Sales and goals.** Conversions tie back to the ad or link that brought the visitor, for 90 days. - **People.** Someone who signs up, signs in or sends a form with an email field is added to [Profiles](https://sporetag.com/docs/customer-profiles), with their email and name. Password and card fields are never read. With **Wait for consent** on, the tag stores and sends nothing about a person until they agree. On Free, the plain tag counts visits only. ## Signs people in with Google or a magic link? Then your site never shows a sign-in form, so the tag has nothing to read. Add one more line, called right after someone signs in: ```js window.sporetag?.('identify', { email, name, id }); ``` `email`, `name` and `id` are the person's email, name and your own user id. Send at least one of email or id. Setup shows this line under **Signs people in with Google or a magic link? Add one more line**, on the install step, and the email to your developer includes it. Sign-up and sign-in forms with an email field need nothing. ## Check it works Go back to Sporetag. On the last setup step, click **Check my site**. Then open your site in a new tab. Your first visit shows up in a minute or two. ## Good to know - Add the tag once per page, not twice. - Single page apps need the tag once, in the main HTML file. See [Add the script](https://sporetag.com/docs/add-the-script). - Need someone else to do it? On step 2 of setup, pick **I have a developer**. We email them the tag and the steps. --- # Your own tracking address > Load the Sporetag tag from a subdomain of your own site, like stats.yourdomain.com, with one DNS record. No proxy or code to run. Source: https://sporetag.com/docs/own-tracking-address Section: Start here Your tag can load from your own domain: `stats.yourdomain.com` instead of `sporetag.com`. You add one DNS record. Sporetag does the rest: the HTTPS certificate, serving the tag and taking its events. What it gets back, honestly: visitors whose blocker looks for Sporetag's address now count. Blockers that follow the DNS record to Sporetag, such as uBlock Origin in Firefox, can still stop it. Nobody can say how many visits that is for your site, so we do not guess. It is on paid plans: Solo, Studio, Agency and Custom. It is the easy version of the [script proxy](https://sporetag.com/docs/script-proxy): nothing to host, and the visitor's real address and country come through without a token. ## Step 1: add the address in Sporetag 1. Open the site, then **Settings**. 2. Under **Your own tracking address**, keep `stats.yourdomain.com` or type another subdomain of your site. 3. Choose **Set up**. Sporetag shows the record to add. Pick a name you do not use for anything else. It cannot be your site itself or `www`. ## Step 2: add one CNAME record | Type | Name | Target | |---|---|---| | CNAME | `stats` | `go.sporetag.com` | Some DNS hosts want the full name, `stats.yourdomain.com`, instead of `stats`. Some call the target **Value**, **Points to** or **Content**. Sporetag shows the steps for your DNS host when it can tell which one you use. ### On Cloudflare Set **Proxy status** to **DNS only**, the gray cloud. With the orange cloud, Cloudflare answers for the name itself and the tag never reaches Sporetag. If your record is orange, Sporetag tells you which record to click. Nothing else on your site changes. ### The name already points somewhere If `stats.yourdomain.com` already points to another service, Sporetag shows where. Changing the record moves the name off that service. If something still lives there, remove the address in Sporetag and pick a new name. ## Step 3: wait for Active Sporetag checks the record when you press **Check now**, when you open Settings and every 15 minutes. Once the record is right, the HTTPS certificate usually takes a few minutes. ## Step 4: paste the new tag, once When the address is **Active**, the tag in Settings changes by itself: ```html ``` Paste it over the old tag in the `` of every page. Until you do, the old tag keeps counting as before. The same tag works with Private mode and 90-day tracking, so switching modes later needs no new tag. Settings says **In use** once visits arrive through it. ## What the address serves - `/js/app.js`: your site's tag, the same as the standard one. - `/js/u`: your site's events, for this site only. - `/`: sends visitors to your site. - Short links, only if you choose **Use it for short links too**. That uses one of your custom short domains. - Everything else: not found. Nothing changes for privacy. The address sets no cookies. With 90-day tracking the tag keeps its first-party id on your own domain, as before, and the same bot filtering and limits apply. ## Remove it Choose **Remove** next to the address. Put the standard tag back on your site first, because a tag that loads from the address stops counting. If short links use the address, archive them first. --- # Script proxy > Serve the Sporetag script and its event endpoint from your own domain with a tiny Cloudflare Worker, so ad blockers drop fewer of your visits. Source: https://sporetag.com/docs/script-proxy Section: Start here A script proxy serves the script and the event endpoint from your own domain. The browser only talks to your site, so blockers that match on our address let it through. Your numbers get closer to the real count. The script proxy is on paid plans: Solo, Studio, Agency and Custom. Free does not include it. ## How it works 1. Your site loads the script from a path on your own domain, such as `/st/s.js`. 2. A small proxy on your domain fetches `https://sporetag.com/s.js` and returns it. 3. Events go to `/st/api/e` on your domain. The proxy forwards them to `https://sporetag.com/api/e`. The script also loads `/st/x.js`, the [automatic events](https://sporetag.com/docs/automatic-events) add-on, from the same path. The snippets below pass it on. A proxy that does not still counts every visit; only the automatic events stop. The site's **Integrations** page (under **Settings**) has each snippet below with your domain and token filled in, ready to copy. ## The visitor's address Behind a proxy, the request that reaches Sporetag comes from your proxy's server. Without help, every visitor would look like the same address in the same country, and unique counts would be wrong. So the proxy passes the visitor's real address in a header. Sporetag only believes that header when the proxy also sends your site's **proxy token**: | Header | Value | |---|---| | `x-sporetag-proxy-key` | The site's proxy token | | `x-sporetag-client-ip` | The visitor's IP address | | `x-sporetag-client-country` | Optional. Two letters, such as `DE` | Make the token on the site's **Integrations** page (under **Settings**), under **Script proxy**. Keep it in your proxy's settings. It never goes into a page, and the browser never sees it. Why a token: anyone can type an `X-Forwarded-For` header, so Sporetag never reads it. Without a valid token, Sporetag uses the address its own network saw, which a browser cannot fake. A proxy without the token still works. It just counts every visitor from the proxy's own address. If the token leaks, press **Make a new token** and update your proxy. The old one stops working at once. ## Cloudflare Worker Create a Worker on a route of your site, such as `shop.example.com/st/*`. Add the token as a secret named `PROXY_KEY` (`npx wrangler secret put PROXY_KEY`). ```js // Sporetag script proxy. Route: /st/* export default { async fetch(request, env) { const url = new URL(request.url); const path = url.pathname.replace(/^\/st/, ''); if (path === '/s.js' || path === '/sa.js' || path === '/x.js') { return fetch('https://sporetag.com' + path + url.search, { cf: { cacheTtl: 300 } }); } if (path === '/api/e' && request.method === 'POST') { const headers = new Headers(request.headers); headers.set('x-sporetag-proxy-key', env.PROXY_KEY); headers.set('x-sporetag-client-ip', request.headers.get('cf-connecting-ip') || ''); headers.set('x-sporetag-client-country', request.cf?.country || ''); return fetch('https://sporetag.com/api/e', { method: 'POST', headers, body: request.body }); } return new Response('Not found', { status: 404 }); }, }; ``` ## Next.js on Vercel A plain rewrite in `next.config.js` works, but cannot add headers, so every visitor counts from Vercel's address. Use middleware instead. Set `SPORETAG_PROXY_KEY` in the project's environment variables. ```ts // middleware.ts import { NextResponse, type NextRequest } from 'next/server'; export const config = { matcher: '/st/:path*' }; export function middleware(req: NextRequest) { const path = req.nextUrl.pathname.replace(/^\/st/, ''); const target = new URL(path + req.nextUrl.search, 'https://sporetag.com'); const headers = new Headers(req.headers); if (path === '/api/e') { headers.set('x-sporetag-proxy-key', process.env.SPORETAG_PROXY_KEY ?? ''); headers.set('x-sporetag-client-ip', (req.headers.get('x-forwarded-for') ?? '').split(',')[0].trim()); headers.set('x-sporetag-client-country', req.headers.get('x-vercel-ip-country') ?? ''); } return NextResponse.rewrite(target, { request: { headers } }); } ``` Vercel sets `x-forwarded-for` itself, so here it is safe to read. ## nginx Inside your `server { }` block: ```nginx location = /st/s.js { proxy_pass https://sporetag.com/s.js; proxy_set_header Host sporetag.com; proxy_ssl_server_name on; } location = /st/sa.js { proxy_pass https://sporetag.com/sa.js$is_args$args; proxy_set_header Host sporetag.com; proxy_ssl_server_name on; } location = /st/x.js { proxy_pass https://sporetag.com/x.js$is_args$args; proxy_set_header Host sporetag.com; proxy_ssl_server_name on; } location = /st/api/e { proxy_pass https://sporetag.com/api/e; proxy_set_header Host sporetag.com; proxy_ssl_server_name on; proxy_set_header x-sporetag-proxy-key "YOUR_PROXY_TOKEN"; proxy_set_header x-sporetag-client-ip $remote_addr; } ``` If nginx sits behind a load balancer, set `$remote_addr` from the real client with the `real_ip` module first. ## The tag Point the tag at your own path, and tell the script where to send events with `data-api`. ```html ``` In [90-day tracking](https://sporetag.com/docs/tracking-modes) the tag loads `sa.js` instead: ```html ``` ## Check it Open your site, then the site's dashboard. The visit shows within a few seconds, with your own country. If every visit shows the same country, the token or the address header is missing. --- # Tracking modes > Private mode is cookieless with no banner. 90-day tracking keeps a 90-day first-party id so a sale ties back to an earlier click. How to choose. Source: https://sporetag.com/docs/tracking-modes Section: Start here Each site has a tracking mode. You choose it in the site's **Settings** tab, under **Tracking mode**. The dashboard always shows which mode a site is in. ## Private (the default) - No cookies and nothing stored in the browser. - Each visitor gets a hash made from a salt that changes every day, the site, the IP address and the browser's user agent. The IP address is never stored. - The same person on the next day counts as a new visitor. - Ad click ids (`gclid`, `gbraid`, `wbraid`, `fbclid`) are read on the landing page and kept with that visit's events only. - The attribution report can only tie a sale to a source within the same visit. Private mode is built so that in most places you do not need a consent banner for it. We are not your lawyer, so check the rules where you and your visitors are. ## 90-day tracking 90-day tracking is on paid plans: Solo, Studio, Agency and Custom. Free does not include it. The script keeps a random first-party id and the latest click ids on your own domain for 90 days. So a sale on day 3 ties back to the ad or short link clicked on day 1. What it stores, on your domain only: | Name | Holds | Kept | |---|---|---| | `_st_id` | A random id, 32 hex characters | 90 days from the last visit | | `_st_ck` | The latest click ids and when they were clicked | 90 days from each click | | `_st_c` | `1` once the visitor agreed, with Wait for consent on | 90 days | Each is a first-party cookie and a copy in `localStorage`. A new Google click replaces older Google click ids; a Meta `fbclid` stays until a newer one comes. If Meta's own pixel set `_fbp` or `_fbc` cookies, the script reads them too, so conversions sent to Meta match better. - The id lives on your domain, not on ours. It is not shared across sites, and Sporetag cannot follow a person from one site to another. - [Profiles](https://sporetag.com/docs/customer-profiles) build on this id. Call `sporetag('identify', { email })` on signup or checkout, and the person's visits join one profile. - Your own server receives the `_st_id` cookie. Send it as `visitor.id` with the [Events API](https://sporetag.com/docs/events-api) to tie a server sale to earlier visits. - Safari and some other browsers may clear script-set storage after 7 days without a visit. Then the next visit starts a new id. - It stores data on the visitor's device. In many places that needs consent first. In the EU and UK this usually means a consent banner. You are responsible for consent on your site. Sporetag gives you a switch to wait for it. ### The tag 90-day tracking uses its own tag. Copy it from the site's **Settings** tab after you switch: ```html ``` Keep the plain tag (`s.js`) after you switch, and visits still count, but no id is kept and no one gets a profile. Sporetag notices this from the visits it receives and shows a warning with the tag to paste. If you switch back to Private, the 90-day tag keeps working but stores nothing. You can swap it back to the plain tag when you like. If the plan ends, the site works as Private. ## Wait for consent Turn on **Wait for consent** in the site's settings. The script then stores nothing, and sends nothing to Meta from the browser, until your consent tool tells it to. Until then it works like Private mode. No consent tool yet? Turn on Sporetag's [simple cookie banner](https://sporetag.com/docs/cookie-banner) in the same Settings tab. It turns on Wait for consent and needs no code. ```js // Call this when the visitor agrees, for example from your consent banner. sporetag('consent', true); // Call this when they say no, or take consent back. It deletes what was stored. sporetag('consent', false); ``` Before consent, `sporetag('identify', ...)` does nothing too. Many consent tools let you run a line of code when a category is accepted. Put this line there. The script remembers the yes for 90 days, so you only need to call it when the visitor answers. ## Honest notes on consent - Private mode does not store anything on the device and keeps no id across days. That is why it usually needs no banner. It still processes the IP address in memory to make the daily hash. - 90-day tracking stores an id and click ids on the device. Rules like the EU ePrivacy Directive usually ask for consent before that, unless it is strictly needed for a service the visitor asked for. Measuring ads is usually not. - Sending conversions to Meta shares the visitor's IP address, browser and click ids with Meta, plus hashed email and phone when you send them. That usually needs consent in the EU and UK in either mode, and a line in your privacy policy everywhere. - Customer profiles keep hashed emails and phones, and the email, name and phone number encrypted unless you turn **Show contact details** off. Name this in your privacy policy. You can delete a customer or forget an email at any time. - Server events you send with the Events API are yours to justify. Send only what your privacy policy covers. When unsure, use Private mode, or 90-day tracking with Wait for consent on. ## Which one to pick | Situation | Mode | |---|---| | You want simple stats and no banner | Private | | You run ads and want sales tied to them | 90-day tracking | | You send conversions to Meta from later visits | 90-day tracking | | Most visitors are in the EU and you have no banner | Private | | You have a consent banner | 90-day tracking with Wait for consent | You can switch a site between modes at any time. Switching does not change data you already have. --- # Cookie banner > Turn on a simple Accept or Decline banner for your site with no code. Nothing is stored until a visitor accepts. You decide whether you need it. Source: https://sporetag.com/docs/cookie-banner Section: Start here Sporetag can show a simple cookie banner on your site. Visitors pick **Accept** or **Decline**. Until they accept, Sporetag stores nothing on their device and works like Private mode. You decide whether your site needs a banner and what it says. This page explains how the banner works. It is not legal advice. See [Tracking modes](https://sporetag.com/docs/tracking-modes) for what each mode stores. ## Turn it on 1. Open the site, then **Settings**. 2. Under **Cookie banner**, pick **Simple banner**. 3. Change the message and the button words if you like, add your privacy page, and pick your button color. 4. Press **Save banner**. The banner shows on your site within 5 minutes. You do not change your tag: the 90-day tag loads the banner on its own while it is on. **See it on a test page** opens a page that shows the banner with your settings, so you can try it before your visitors do. The banner works in [90-day tracking](https://sporetag.com/docs/tracking-modes), on paid plans. Private mode stores nothing on the device, so it has nothing to ask. ## What it does - Turning it on also turns on **Wait for consent**. Before a visitor answers, Sporetag stores nothing and sends nothing to Meta from the browser. Visits still count, the Private mode way. - **Accept** is the same as `sporetag('consent', true)`: Sporetag may now keep its id and click ids for 90 days. - **Decline** is the same as `sporetag('consent', false)`: anything stored is deleted. - The answer is kept for 180 days in a first-party cookie, `_st_b`, which holds only `1` or `0`. The banner does not show again until then. - Form capture and tap counting wait for **Accept** too. ## Google Consent Mode If your site runs Google tags (Google Ads, Google Analytics or Tag Manager), the banner passes each answer to Google as a Consent Mode v2 update: `ad_storage`, `ad_user_data`, `ad_personalization` and `analytics_storage`, all granted on **Accept** and all denied on **Decline**. On later pages it passes the saved answer again. Sites without Google tags get nothing extra. Google also needs a starting state before its tag loads. Paste this above your Google tag. It starts from the visitor's saved answer, or denied until they pick: ```html ``` The same snippet is under **Cookie banner** in the site's Settings, ready to copy. ## Let visitors change their answer Add a link to `#sporetag-consent` anywhere on your site, such as in the footer: ```html Cookie settings ``` A click on it opens the banner again. ## How it looks - It sits at the bottom of the screen, over the page. Nothing on the page moves when it shows. - **Match your site's theme** (the default) follows your site: a dark or light class or `data-theme` on the page, else how dark the page background is, else the visitor's device. It switches when your site does. You can pick **Always light** or **Always dark** instead. - The Accept button uses your color, with black or white text, whichever reads better. - Both buttons are the same size and at least 44 pixels tall. On narrow phones they sit under the message and fill its width. ## Accessibility - The banner is a labeled region named "Cookie choice", placed first in the page, so keyboard and screen reader users meet it first. It does not trap focus. - Both buttons work with the keyboard and show a clear focus ring. - With reduced motion turned on, it appears without sliding in. ## Your own banner instead If you already use a consent tool, keep the banner off. Turn on **Wait for consent**, and have your tool run this when a visitor agrees: ```js sporetag('consent', true); ``` See [Tracking modes](https://sporetag.com/docs/tracking-modes#wait-for-consent). --- # Bot filtering > How Sporetag keeps bots, crawlers and automated browsers out of your numbers, and why visits from data centers still count as people. Source: https://sporetag.com/docs/bot-filtering Section: Start here A lot of web traffic is not people. Sporetag filters it in a few layers, so your numbers stay close to real visits. ## What is dropped These events are never written: - A user agent that names a crawler, a link preview, an uptime monitor, a headless browser or an HTTP library such as `curl`. An empty user agent and a bare `Mozilla/5.0` count as bots too. - Requests from verified bots, such as search engine crawlers. - Browsers that report `navigator.webdriver`, which most automation tools do. The script sends nothing from them. - Browsers that cannot send a beacon. Real browsers today all can. ## What is marked What gets through is written with a set of flags, so it can be judged again later. | Flag | Means | |---|---| | Unknown user agent | The user agent names no browser and no operating system | | Bot score | The network's bot score says it is likely automated | | Data center | The request came from a known cloud or hosting network | The dashboard leaves out events with either of the first two flags. ## Why data centers still count Many real people browse through a VPN or a privacy relay. Those often run in data centers. If we dropped every data center visit, we would undercount real people. So a data center flag on its own does not remove a visit. ## Pageviews need a visible tab The script waits until the tab has been visible for 1.5 seconds before it counts a pageview. Tabs that open in the background and close unseen are not counted. That also stops many simple bots that load a page and leave at once. --- # Autopilot > Plain-English summaries, a simple view for clients, alerts that watch your sites, setup that runs itself and a weekly plan. Source: https://sporetag.com/docs/autopilot Section: Start here Autopilot does the watching for you. It tells you what is happening in plain words, warns you when something needs a look, finishes setup on its own where it can, and suggests a few next steps each week. Nothing changes on your site or account until you press Apply. ## What's happening On the **Overview**, each site has a short briefing, and every client's view starts with one. It is three to five short sentences written from your own numbers. For example: "38 people visited in the last 7 days, 12 more than the 7 days before." Each sentence links to the place that proves it, such as the dashboard filtered to that source. - On the Overview they cover the last 7 days. On a client's view they follow the period picked. - On a client's view, up to two [card sentences](https://sporetag.com/docs/dashboards#what-the-card-sentences-mean) follow, such as "Signups up 22% over the 7 days before, mostly from Meta (+31)." - When a period has fewer than 10 visitors, you see "Not enough visits yet to spot trends." instead of guesses. - Ad cost per signup or sale shows only when Sporetag worked out which ads brought them. - Money is shown in your reporting currency. Other currencies are converted at the European Central Bank rate for each day. - With filters on, the summary steps aside, since it covers the whole site. When the Assistant is on, **Explain more** asks it to say what stands out. It counts as one Assistant message. ## The simple view for clients Most clients want one page with big numbers and no jargon, so a client you invite by email opens the simple view. Set it up in the site's **Reports**, then **Share**, under **Simple view**: - Pick the three big numbers. The default is visitors, signups or sales, and ad cost per signup or sale. A number with no data is swapped for the next useful one. - Pick what counts as a signup or sale, or let Sporetag pick. - Invited clients start on it. Press **Show full dashboard** next to a client to give them the full dashboard instead. The share link shows it only when you tick **Show the simple view on the share link**. Clients see the summary, the three numbers, the [targets](https://sporetag.com/docs/dashboards#monthly-targets) on the dashboard they see, where visitors came from as a ranked list in plain words ("Google", "Instagram", "Your email"), and the latest signups or sales with where each came from. Names, emails and phone numbers are never shown. A **See the full dashboard** button opens everything else. Press **Preview** to see what they see. ## Alerts Open **Alerts** in the sidebar to see every alert on every site, newest first. Each one links to where you fix it. Tap a site's name at the top to see only that site, its uptime, and **Alert settings**, where you pick which alerts it sends. - **Ad spend with no signups today**: your ads spent more than the amount you set and no signup came in by the hour you pick. Default: over 50, by 3 PM. - **Traffic dropped by half**: yesterday brought half or less of a usual day for that weekday, so a quiet Monday is compared with other Mondays. Sites with fewer than 20 visitors a day are left out. - **Unusual change**: a number moved far from a usual day. See [Unusual changes](#unusual-changes) below. - **A target falls behind**: on day 10 or day 20 of the month, a card's [monthly target](https://sporetag.com/docs/dashboards#monthly-targets) is Behind, or Over for a number where lower is better. Once per target per month. - **Tag stopped sending**: no visits for the hours you set (default 12) on a site that usually has them. - **Tracking needs a fix**: a [tracking health](https://sporetag.com/docs/tracking-health) check turned red, such as orders no longer tying to visits or Meta sends failing. Once per break: it alerts again only after the check has passed in between. - **Big day**: yesterday was your best day in 4 weeks, for signups or visitors. - **New signup**: the first signup of the day, within 15 minutes. Off by default. At most one alert of each kind goes out per site per day. Nothing is sent during quiet hours (9 PM to 8 AM by default, in the time zone you pick); what still holds true goes out after. Alerts go by email to you, and to invited clients if you turn that on ("Tag stopped sending" and "Tracking needs a fix" stay with you). Texts to you are (when shipped). The weekly report already covers the good news of the week, so there is no separate weekly alert. ### Emails you get **Alerts** also lists every email Sporetag sends you, each with its own switch. A switch works the moment you tap it. - **Alerts**, **Site down, SSL and domain** and **Weekly plan**: for every site, or for the site you picked at the top. - **Digest**: every site that needs you, daily or weekly (Studio and Agency). Its time, and Slack or Teams, are under **Digest and chat**. - **Reports sent to you**: each report that includes you. - **From Sporetag**: milestones, setup tips and plan reminders. Security, billing and failed payment emails always reach you, so they have no switch. ### Unusual changes Each morning Sporetag compares yesterday with the same weekday in the 8 weeks before. It needs 4 of those weeks first. "Usual" is the middle value of those days, so one odd week does not move it. A change counts only when it is 40% or more and well outside how much the number usually swings. There is nothing to set. It watches: - Visitors, from 30 on a usual day. - Your goal's conversions, from 8 on a usual day, and its conversion rate, from 200 visitors and 8 conversions. - Sales from connected stores, from 5 orders on a usual day. - Visits from each of your top 5 sources, from 20 on a usual day. - Ad spend per platform, from 20 a day in the account's currency, and cost per result where the platform reports results. Only once the platform's numbers for yesterday are in. Each alert says what changed and, when the data shows it, the likely cause: a campaign that stopped or started spending, the one source behind most of a change, the tag that stopped, or one big order. When the data shows no cause, the alert says none. For example: "Visits from Facebook fell 70% yesterday: 18, from about 60 on a usual Wednesday. Meta campaign "Fall sale" stopped spending on Oct 21." A change that lasts several days is one change: it alerts once, on its first day. What **Traffic dropped by half**, **Big day** or **Tag stopped sending** already told you is left out. **Alerts** lists the last 30 days of changes. Tap **Mute** next to one to stop hearing about that number or source. Muted ones are under **Muted**, where **Unmute** brings them back. ### On your phone Open **Alerts** and find **Phone alerts**. Tap **Turn on for this device**, then allow alerts when your phone asks. Each alert is one short line; tap it to open the page that shows why. - **Wins**: first sale of the day, milestones (going live, a first sale, 100 visitors), a record day, and the weekly summary. - **Problems**: tag stopped, site is down (and back up), traffic halved, unusual changes, a target behind, tracking needs a fix, ad spend with no results, and an SSL certificate or domain about to end. Uptime, SSL and domain checks come with paid plans. Turn each one on or off, and set quiet hours. Alerts that come in quiet hours wait until they end. Phone alerts follow your own switches, even when a site's email alert is off. On iPhone and iPad, alerts work only in the Home Screen app, on iOS 16.4 or later. In Safari, tap **Share**, then **Add to Home Screen**. Open Sporetag from your Home Screen and turn alerts on there. Signing out on a phone stops its alerts. ## Setup that runs itself When you add a site through **Set up my site**, Sporetag reads your home page once: - It works out what the site is built with (Shopify, WordPress, Wix, Squarespace, Webflow, Framer, Next.js, Ghost, or your own code) and opens the right install steps. - **Email these steps to my developer** sends them the tag and those steps. - It works out what kind of site it is (a store, a site that gets leads, or a content site) and starts your first dashboard with the right charts. For the first 7 days, Sporetag checks your site for the tag every 15 minutes. When it finds the tag, or a first visit, you get one email and an "It works." banner on the Overview. After the first day, Sporetag looks at what your site already sends, like a "Signup" event or a /thank-you page, and suggests goals. Add one with one tap, or turn on **Add suggested goals without asking** in the Alerts settings. ## The weekly plan Every Monday morning (and any time you press **Make a plan**), each site's briefing on the **Overview** shows three to five next steps, each tied to a real number. Some run with Apply: add a goal, set up an abandoned checkout email, send new signups a welcome email, schedule a weekly client report, or build a signups dashboard. Some open a page, like connecting an ad account. Some are advice, like moving budget to the ad platform that brings signups for less; Sporetag never changes your ads. - **Apply** first shows exactly what will be made. Press **Apply** again to do it. Applied steps are in the Assistant's **Changes** list, with **Undo** where the feature has one. - **Not now** hides a step for a week. **Dismiss** hides it for good. - With the Assistant on, it picks and words the steps from a fixed list of what Sporetag can do. A plan counts as one Assistant message. If any number in its words is not in your data, that step keeps the plain wording instead. With the Assistant off, or no messages left this month, the steps come from the same numbers by fixed rules. - The plan is emailed to you each Monday, with a link back to Sporetag. Nothing is applied from the email. Turn the email off in **Alerts**, under **Emails**. - The Assistant never sees names, emails or phone numbers, and treats text from your website as data, not instructions. --- # Your week email > A short email every Monday morning with each site's visitors, top source and conversions, and the change from the week before. On every plan, off in one click. Source: https://sporetag.com/docs/your-week Section: Start here Every Monday morning Sporetag sends you **Your week**: how each of your sites did in the week that just ended. It comes on every plan, Free included, so you can see your numbers without signing in. ## What it says For each site that had visitors, busiest first: - **Visitors** in the week, and the change from the week before, such as "+12% on the week before". - **Conversions**, when the site has goals, with the same change. - **Top source**: where most visitors came from, such as Google or Instagram, and how many. The week is Monday to Sunday in your time zone. Up to 8 sites are shown; the rest are a count and a link. The button opens your dashboard. ## When it comes Monday from 8 AM in your time zone: the first site's alert time zone, set in the site's **Settings** under **Alerts**, else the site's own time zone. It is not sent when: - No site had a visit all week. - You turned it off. - Your account gets the **Digest** from the Overview by email (Studio and Agency). The digest covers every site already, so you get one Monday email, not two. Turn the digest off and **Your week** comes back. ## Turn it off Press **Unsubscribe** at the bottom of the email, or open **Settings** and clear **Your week** under **Emails from Sporetag**. Turn it back on in the same place. The weekly plan from [Autopilot](https://sporetag.com/docs/autopilot#the-weekly-plan) and the [client reports](https://sporetag.com/docs/client-reports) you send are separate emails with their own settings. --- # Custom events and goals > Count signups, purchases and button clicks with sporetag() custom events, then turn events and pages into goals you can see in the dashboard. Source: https://sporetag.com/docs/custom-events-and-goals Section: Measure Pageviews tell you who came. Events and goals tell you who did something. ## Send a custom event Once the script is on the page, call `sporetag` with an event name. ```js sporetag('Signup'); ``` You can add details as props. Keep values short: plain strings or numbers. ```js sporetag('Purchase', { plan: 'Pro', value: 49, currency: 'USD' }); ``` Events from the browser count toward your monthly allowance like pageviews. [Automatic events](https://sporetag.com/docs/automatic-events), such as outbound link clicks and file downloads, are free and need no code. The script loads with `defer`, so call `sporetag` from code that runs after the page has loaded, such as a click handler or a form's submit handler. ## Make a goal A goal is something you want to count as a win, like a sale or a signup. Open the site, then **Goals**. The common goals take one tap and no code: | Goal | Counts | What it needs | |---|---|---| | Someone buys | Each paid order (the `Purchase` event) | [Stripe](https://sporetag.com/docs/stripe-connector) or [Shopify](https://sporetag.com/docs/shopify-connector) connected, the [Events API](https://sporetag.com/docs/events-api), or `sporetag('Purchase')` | | Someone fills in a form | Each form sent with an email or phone field (the `Form sent` event) | 90-day tracking. Adding the goal turns on [form capture](https://sporetag.com/docs/customer-profiles#people-from-sign-ups-and-forms) | | Someone books or calls | Taps on your phone number, email address and booking links such as Calendly and Cal.com (the `Book or call` event) | 90-day tracking. Adding the goal turns on tap counting | | Someone reaches a thank-you page | Visits to the page people see after they buy or sign up | Nothing. Pick the page from your own pages, or type it | Form sent and Book or call come from a small add-on that the 90-day tag loads only while its switch is on. Like the rest of 90-day tracking, it sends nothing until the visitor agrees when **Wait for consent** is on. Booking links count when a visitor taps a link or button that opens them. A booking made inside an embedded Calendly widget counts too. ### Custom goals Under **Custom goal** there are two kinds. | Kind | Counts when | |---|---| | A page is visited | A visitor opens a matching path, such as `/thanks`. Use `*` for any part, like `/blog/*` | | An action happens | An event with this name arrives, such as `Signup` | A site can have up to 20 goals, and your plan may allow fewer. A new goal counts past visits too. ## See goals in the dashboard Each goal shows its conversions and its conversion rate: the share of visitors who reached it. Filter by source, campaign or short link to see which one brought the people who converted. ## Send a goal to Meta On the site's **Integrations** page (under **Settings**), tick a goal under **Goals to send** and its conversions go to the Meta Conversions API, from the browser and from your server. See [Meta Conversions API](https://sporetag.com/docs/meta-conversions-api). ## Events from your server Some events only your server knows about, like a paid order. Send those with the [Events API](https://sporetag.com/docs/events-api). --- # Automatic events > Outbound link clicks, file downloads, 404 pages, scroll depth and form submits, counted with no code and free of your monthly allowance. Source: https://sporetag.com/docs/automatic-events Section: Measure Some things are worth counting on every site. Sporetag counts these five for you, with no code: | Event | Counts | Shows | |---|---|---| | `Outbound link` | Clicks on links to other sites, like your booking page or a map | Each link, by host and path | | `File download` | Clicks on PDFs, menus, price lists, zips, documents, audio and video files, and any link with a `download` attribute | Each file | | `Page not found` | Visits to your 404 page | Each missing page, and where people came from | | `Scroll depth` | How far down each page people read: 25, 50, 75 and 100% | The share of views of each page that reached each mark | | `Form submit` | Every form sent on your site, except search boxes | Each form, by its name or id | All five are on for every site. Turn any of them off in the site's **Settings**, under **Automatic events**. The reports are in the site's **Goals**, under **Events**. ## What they never read - No form field. A form submit names the form, never what was typed. - No query string or `#` part of an address. A link to `calendly.com/acme?email=ann@example.com` counts as `calendly.com/acme`. - No cookie and no storage. Automatic events work the same in Private mode and 90-day tracking. ## Free of your allowance Automatic events never count toward your plan's monthly events. Turning them on costs nothing. ## Make one a goal Under **Events**, **Make it a goal** turns outbound link clicks, file downloads or form submits into a goal in one tap. It counts past events too. Scroll depth and 404 pages are reports, not goals. ## 404 pages Sporetag looks for "404" or "not found" in the page title. If your 404 page says something else, type its words under **More options** in the Automatic events card. Or add `data-sporetag-404` to any tag on that page: ```html
``` ## Scroll depth, exactly Each page view reaches a mark once. A visitor who reads half a page, switches tabs, then comes back and reads to the end counts once at 50% and once at 100%, never twice at 50%. A page shorter than the screen counts as read to the end. ## How it loads The tracking script loads a small add-on, `x.js`, with your site's switches already set. It is under 1.5 KB. With every switch off, the file is empty. Behind a [script proxy](https://sporetag.com/docs/script-proxy), pass `/st/x.js` on like the script itself. Automatic events are kept out of customer profiles and their timelines when they are not something the person chose to do: scroll depth and 404 pages. --- # Tracking health > One score per site that says whether you can trust its numbers, with a short list of checks and a one-tap fix for each. Source: https://sporetag.com/docs/tracking-health Section: Measure Every site gets a tracking health score out of 100: the share of the checks that apply that pass, so 9 of 10 checks is 90. It shows as a ring that fills to the score: in the **Tracking health** badge next to the site's name on its dashboard and on each site in your sites list, and in each site's tiles on the [Overview](https://sporetag.com/docs/agency-overview). Tap the badge for the checks. The ring's color says the status. Green means all good. Amber means something is worth a look. Red means something needs a fix: some numbers are missing or wrong until it is fixed. ## The checks | Check | Passes when | The fix | |---|---|---| | Tag sends visits | A visit came in during the last 24 hours, or the site is quiet anyway | Check the tag on your site | | Tag on every page | Each page we read, and each page your short links lead to, loads the tag | Add the tag to the pages named | | 90-day tag | With 90-day tracking, your pages load the 90-day tag, not the plain one | Swap in the 90-day tag | | One tag per page | No page loads the tag twice, which would count each visit twice | Remove the extra tag | | Orders tied to a visit | 60% or more of store and CRM orders in 30 days came from a tracked visit | The Shopify snippet, the Stripe visitor id, or 90-day tracking | | Ad clicks arrive tracked | 40% or more of the clicks your ad accounts report reach your site with their click id | Google auto-tagging, or ad links that keep their click id | | Visitors who say yes | When the site asks for consent, 30% or more of visitors say yes | Check or shorten the banner, or connect your consent tool | | Conversions reach Meta | 95% or more of this week's sends to Meta arrived | See the failed sends | | Goals counting | The site has goals, and each counted something in 30 days | Add or check goals | | No checkout as a source | No payment page or your own domain starts visits | **Count them as my site**, in one tap | | Ads name their campaign | 80% or more of visits from ads carry UTM tags | Add the ad URL template | A check that does not apply yet is listed under **Not checked yet** with what it needs, like "Connect Shopify or Stripe to check this." It does not count toward the score. Some ad blockers stop the tag from loading, so a share of clicks and orders never reaches any tool. The bars above leave room for that. ## Checkout pages as a source A buyer who pays on PayPal or a Stripe page and comes back would otherwise look like a new visit from that page, and the ad that brought them would lose the sale. **Count them as my site** treats those pages as part of your site from then on: the visit carries on, and the credit stays with the ad. ## How often Sporetag checks each site about once an hour, and reads your home page and up to four pages it links to once a day. **Check again** on the health page does it all now. ## Alerts When a check turns red, Sporetag sends one **Tracking needs a fix** alert, like the other [Autopilot alerts](https://sporetag.com/docs/autopilot#alerts). It goes to you only, never to invited clients, and only once per break. A tag that stops sending has its own alert, **Tag stopped sending**. --- # Funnels > See how many people make each step to a sale or a signup, where the rest leave, how long each step takes, and which sources finish best. Source: https://sporetag.com/docs/funnels Section: Measure A funnel is the path people take to a win, step by step: visit the site, view a product, open the cart, start checkout, buy. It shows how many make each step, and where the rest leave. Funnels are on Solo, Studio and Agency. ## Your first funnel is ready Open the site, then **Goals**, then **Funnels**. Sporetag builds a funnel for you from your [goals](https://sporetag.com/docs/custom-events-and-goals) and the pages people really visit. A shop gets visit, product, cart, checkout, then the sale. A lead site gets visit, pricing or contact, then the form. It is marked **Suggested**. Tap **Save** to keep it as it is, or **Change steps** to start from it. No goal yet? Add one on the **Goals** tab and the suggestion appears. ## Read it - **The sentence on top** names the step where most people leave. - **Started, Finished and Conversion** sum it up. Conversion is the share of starters who finished, with the change from the period before. - **Each bar** is the people who reached that step, and their share of the starters. - **Between the bars:** the share who went on, how many left, and the typical (median) time the next step took. - **The thin mark** on each bar is where the period before ended up. Pick 7, 30 or 90 days on top. **Split by** shows the same funnel by source, campaign or device, so you can see that Instagram visitors finish twice as often as Google ones. ## See who left With 90-day tracking, the number of people who left at a step is a link. It opens the visitor profiles behind it, newest first, so you can see where they came from and what they did. Profiles start after consent when your site waits for it, so the list can be shorter than the count. ## Build or change a funnel **New funnel** opens the builder, filled with the suggested steps. | Step | Counts when | Example | |---|---|---| | Page | Someone views a page. Use `*` for any part | `/products/*`, `/cart`, `/*` for any page | | Event | Your site or the Events API sends that event | `Signup`, `Add to cart` | | Goal | One of your goals is reached | Purchase, Form sent | Steps must happen in this order. A later step never counts from the same event as the step before it. **Count the steps** sets how far apart they can be: - **In one visit:** all steps in the same visit (one visitor on one day). This is all Private mode can do. - **Within 1, 7 or 30 days, across visits:** for sites with [90-day tracking](https://sporetag.com/docs/tracking-modes). Someone who looks today and buys on Friday counts as one finish. A site can have 10 funnels with 2 to 8 steps each. ## On dashboards and in reports On any dashboard, tap **Add card**, type "funnel" and pick **Funnel**. It starts on the suggested funnel. To show another, open the card's menu, choose **Edit this widget** and pick it under **Funnel**. It shows for the dashboard's period, on shared client dashboards too. Client reports have a **Funnel** block. The Store, Lead gen and SaaS [dashboards](https://sporetag.com/docs/dashboards#boards-built-for-you) start with the suggested funnel. ## How it is counted - A funnel starts when step 1 happens inside the period. Later steps may land after the period ends, while they are within the window. - If someone starts more than once, the try that got furthest counts. - Bots never count, as everywhere in Sporetag. - A funnel reads the last 90 days at most. On a very busy site a funnel reads the first 50,000 matching events of a period, and the page says when that limit was reached. --- # Events API > Send signups and sales from your server to Sporetag with POST /api/v1/events and a per-site secret key. Examples in Node, Python, PHP and curl. Source: https://sporetag.com/docs/events-api Section: Measure The Events API records an event from your server. Use it for things the browser never sees, or cannot be trusted with: a paid order, a webhook from Stripe or Shopify, a signup confirmed by email. Server events count toward goals and the attribution report like browser events. If a goal is set to send to Meta, server events go there too. See [Meta Conversions API](https://sporetag.com/docs/meta-conversions-api). The Events API is on paid plans: Solo, Studio, Agency and Custom. Free does not include it. ## Endpoint ```text POST https://sporetag.com/api/v1/events Authorization: Bearer st_sk_... Content-Type: application/json ``` Each site has its own secret keys. Make one on the site's **Integrations** page (under **Settings**), under **Events API**. The key is shown once, when you make it. Sporetag stores only a hash of it. Keep the key on your server. Never put it in a page, an app or a public repo. The endpoint sends no CORS headers, so a browser page cannot call it. If a key leaks, press **Rotate**: you get a new key and the old one stops working at once. **Revoke** stops a key without a new one. ## Fields Send one event per request, as a JSON object. | Field | Type | Notes | |---|---|---| | `name` | string | Required. The event name, such as `Purchase`. Up to 120 characters | | `url` | string | The page the event belongs to. Must be on the site's domain | | `timestamp` | number or string | When it happened: Unix seconds, milliseconds, or ISO 8601. Up to 7 days back. Default: now | | `event_id` | string | Your unique id. The same id twice is counted once (kept 30 days) | | `value` | number | Order value, such as `49.00` | | `currency` | string | Three letters, such as `USD`. Required with `value` | | `order_id` | string | Your order number | | `email` | string | Hashed with SHA-256 on arrival if you send it plain | | `phone` | string | Same as email. Use the full number with country code | | `ip` | string | The visitor's IP address, if you have it | | `user_agent` | string | The visitor's browser user agent, if you have it | | `visitor` | object | Or send `ip`, `ua` and `id` together here. `id` is the visitor's first-party id | | `gpc` | boolean | `true` when the visitor's browser sent Global Privacy Control. Also accepted as `visitor.gpc` | | `click_ids` | object | Any of `fbclid`, `gclid`, `gbraid`, `wbraid`, `fbc`, `fbp` | | `props` | object | Extra details, with string or number values, up to 20 keys | | `kind` | string | For [customer profiles](https://sporetag.com/docs/customer-profiles): `order`, `refund`, `email_opened`, `sms_clicked`, `call` and more. See [Bring your data together](https://sporetag.com/docs/bring-your-data-together) | | `source` | string | The tool the event came from, such as `klaviyo`. Lowercase | | `external_ids` | object | Ids in other tools, such as `{"stripe_customer": "cus_123"}` | | `payload` | object | Short details for a customer item, up to 12 values | Ids (`event_id`, `order_id`, `visitor.id`) use up to 100 letters, digits and `. _ - : ~ @`. A refund is `kind: "refund"` with the amount refunded as `value` and the sale's `order_id`. When that sale went to Google Ads or Microsoft Ads, its value there drops by the refund. See [Refunds](https://sporetag.com/docs/send-results-to-ad-accounts#refunds). ### Email and phone Sporetag normalizes them the way Meta asks, then hashes them with SHA-256: - Email: spaces trimmed, then lowercase. - Phone: digits only, leading zeros dropped. `+1 (555) 123-4567` becomes `15551234567`. A value that is already a SHA-256 hash (64 hex characters) is used as it is. Neither the plain email or phone nor their hashes are stored with your stats. The hash goes to Meta when a goal sends to Meta. ### Customer profiles When the site is in [90-day tracking](https://sporetag.com/docs/tracking-modes), `email`, `phone`, `visitor.id` and `external_ids` also find or make the [customer profile](https://sporetag.com/docs/customer-profiles). The hashes are kept on the profile, and the email, name and phone too (encrypted) while **Show contact details** is on. A `value` adds an order to the customer. The answer then has `customer_id`. With a `kind` other than `event` or `order`, the request adds an item to the customer's stream only. It does not count as an event. See [Bring your data together](https://sporetag.com/docs/bring-your-data-together). ### Global Privacy Control A browser with Global Privacy Control on sends the header `Sec-GPC: 1` with every request, to your server too. Pass it on as `gpc: true`. Sporetag treats it exactly as it treats the signal on a visit: the event still counts in your stats, but nothing about it goes to Meta or any other ad platform. In [90-day tracking](https://sporetag.com/docs/tracking-modes), with `visitor.id`, the signal is kept for that visitor, so their later sales are not sent either. ```js gpc: req.get('sec-gpc') === '1', ``` ### Tying the event to a visit - `ip` and `user_agent` from the visitor's own browser give the same visitor hash as their visit that day. The event then joins that visit's source, campaign and short link. - In [90-day tracking](https://sporetag.com/docs/tracking-modes), the script keeps a first-party id in the cookie `_st_id` on your domain. Your server gets it with every request. Send it as `visitor.id`, and the event joins visits from up to 90 days back. - Click ids tie the event straight to an ad click. Without any of these the event still counts, but it cannot be tied to a source. Events count at the time Sporetag receives them. `timestamp` is what goes to Meta as the event time. ## Node ```js await fetch('https://sporetag.com/api/v1/events', { method: 'POST', headers: { authorization: `Bearer ${process.env.SPORETAG_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({ name: 'Purchase', url: 'https://shop.example.com/thanks', event_id: `order-${order.id}`, value: order.total, currency: 'USD', email: order.email, ip: req.ip, user_agent: req.get('user-agent'), visitor: { id: req.cookies._st_id }, }), }); ``` ## Python ```python import os, requests requests.post( "https://sporetag.com/api/v1/events", headers={"Authorization": f"Bearer {os.environ['SPORETAG_KEY']}"}, json={ "name": "Purchase", "url": "https://shop.example.com/thanks", "event_id": f"order-{order.id}", "value": order.total, "currency": "USD", "email": order.email, }, timeout=5, ) ``` ## PHP ```php $ch = curl_init('https://sporetag.com/api/v1/events'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . getenv('SPORETAG_KEY'), 'Content-Type: application/json', ], CURLOPT_POSTFIELDS => json_encode([ 'name' => 'Purchase', 'url' => 'https://shop.example.com/thanks', 'event_id' => 'order-' . $order->id, 'value' => $order->total, 'currency' => 'USD', 'email' => $order->email, 'visitor' => ['id' => $_COOKIE['_st_id'] ?? null], ]), ]); curl_exec($ch); curl_close($ch); ``` ## curl ```sh curl https://sporetag.com/api/v1/events \ -H "Authorization: Bearer $SPORETAG_KEY" \ -H "Content-Type: application/json" \ -d '{"name":"Purchase","event_id":"order-1042","value":49,"currency":"USD"}' ``` ## From a Stripe webhook When Stripe tells your server that a Checkout Session is complete, send a `Purchase` with the session id as the `event_id`. A retried webhook then never counts twice. ```js // Inside your checkout.session.completed handler, after checking the signature. const s = event.data.object; await fetch('https://sporetag.com/api/v1/events', { method: 'POST', headers: { authorization: `Bearer ${process.env.SPORETAG_KEY}`, 'content-type': 'application/json' }, body: JSON.stringify({ name: 'Purchase', event_id: s.id, timestamp: event.created, value: s.amount_total / 100, currency: s.currency.toUpperCase(), order_id: s.client_reference_id ?? undefined, email: s.customer_details?.email, visitor: s.metadata?.st_id ? { id: s.metadata.st_id } : undefined, }), }); ``` To tie the sale to the visit, copy the `_st_id` cookie into the Checkout Session's `metadata.st_id` when you create it. ## From a Shopify webhook Subscribe to `orders/paid` in Shopify. In your handler, after checking the `X-Shopify-Hmac-Sha256` header: ```js const o = JSON.parse(rawBody); await fetch('https://sporetag.com/api/v1/events', { method: 'POST', headers: { authorization: `Bearer ${process.env.SPORETAG_KEY}`, 'content-type': 'application/json' }, body: JSON.stringify({ name: 'Purchase', event_id: `shopify-${o.id}`, timestamp: o.processed_at ?? o.created_at, value: Number(o.total_price), currency: o.currency, order_id: String(o.order_number), email: o.email, phone: o.phone ?? o.customer?.phone ?? undefined, ip: o.browser_ip ?? undefined, user_agent: o.client_details?.user_agent ?? undefined, }), }); ``` You can skip this code: the [Stripe connector](https://sporetag.com/docs/stripe-connector) and the [Shopify connector](https://sporetag.com/docs/shopify-connector) read sales for you. If you keep both, send the same `event_id` (the Checkout Session id, or `shopify-` and the order id) and each sale is counted and sent to Meta once. ## Answers | Status | Means | |---|---| | `202` | Accepted. The body has `event_id` and the names of the goals it reached. A repeated `event_id` answers `202` with `"duplicate": true` | | `400` | A field is not valid. `field` names it and `error` says why | | `401` | The key is missing, wrong or revoked | | `403` | The site's plan does not include the Events API, or a `kind` was sent while the site is in Private mode | | `413` | The body is over 16,000 bytes | | `415` | The body is not sent as `application/json` | | `429` | More than 300 events a minute on one key. Wait a minute and try again | Send events in the background or after your response, so a slow network never holds up your checkout. --- # Notes on charts > Mark launches, sales and changes on your chart. Sporetag adds notes for new goals, campaign starts and big days, and reports include them. Source: https://sporetag.com/docs/chart-notes Section: Measure A note says what happened on a day, so a jump on the chart has a reason next to it. Notes show as a small flag on the main chart. Point at the day to read them. ## Add a note 1. Open your site's dashboard. 2. Click **Add a note** under the main chart. Once the period has notes, the button reads **Notes (3)**. Or click a day on the chart: its [breakdown](https://sporetag.com/docs/dashboards#see-what-makes-a-number) opens, with **Add a note** at the foot. 3. Pick the day, write a few words, like "Launched the spring sale", and click **Add note**. Notes are up to 140 characters. A site can have 500. ## Notes Sporetag adds These come from data Sporetag already has. You do not need to do anything. | Note | When | |---|---| | Tracking started | The day of the site's first tracked visit. Days before it show as no data, not zero | | Sporetag's own numbers start | The day imported [history](https://sporetag.com/docs/import-history) hands over to Sporetag's own count | | Tracking tag found on the site | Sporetag found the tag, on a site with imported history, where it takes the place of Tracking started | | Tracking tag stopped sending | The tag went quiet (an [alert](https://sporetag.com/docs/autopilot)) | | Goal added | You added a goal | | Campaign started | An ad campaign's first day of spend, from connected or imported [ad spend](https://sporetag.com/docs/meta-ads-spend) | | Big day | A day with at least twice the usual visitors | | Unusual change | A number far from a usual day for that weekday, with its likely cause when the data shows one (see [Unusual changes](https://sporetag.com/docs/autopilot#unusual-changes)) | ## Remove a note Click **Notes** under the chart and click the cross next to a note. Notes Sporetag added are marked **Automatic**. A note you wrote is deleted. A note Sporetag added is hidden for good. ## Where notes show - On the main chart of the dashboard, and on [shared dashboards](https://sporetag.com/docs/client-dashboards), so clients see them too. - In the breakdown for a day on a chart, under its number. - In [client reports](https://sporetag.com/docs/client-reports), with a **What happened** block. The Monthly performance template has one. - To the [Assistant](https://sporetag.com/docs/assistant), so when you ask why traffic jumped it can point to the note for that day. --- # Meta Conversions API > Send conversions from Sporetag to Meta with the Conversions API. Paste a pixel id and access token, mark goals, test with a test event code. Source: https://sporetag.com/docs/meta-conversions-api Section: Measure The Meta Conversions API (CAPI) lets you send conversions to Meta from a server instead of only from the pixel in the browser. Blockers and short cookie lifetimes make the browser pixel miss sales. Server events fill the gap, and Meta can match them back to the ad. Sporetag does the server part for you. You paste two values, mark which goals to send, and Sporetag sends them. It is on paid plans: Solo, Studio, Agency and Custom. Free does not include it. ## What you need - A Meta pixel for your site. Meta also calls it a dataset. - Its **pixel id**, a number. - An **access token** for the Conversions API. ## Get the access token 1. Open [Meta Events Manager](https://business.facebook.com/events_manager2). 2. Pick your pixel (dataset) in the list on the left. 3. Open the **Settings** tab. 4. Scroll to **Conversions API** and find **Set up manually**. 5. Press **Generate access token**. Copy it right away. Meta shows it once. The pixel id is at the top of the same Settings tab. ## Connect a site 1. Open the site in Sporetag, then **Settings**, then **Integrations**. 2. Under **Meta Conversions API**, paste the pixel id and the access token. 3. Press **Save**. The token is encrypted before it is stored. Nobody can read it back in the dashboard, not even you. To replace it, paste a new one. **Disconnect** deletes it. If the setup card says Meta sending is not switched on yet, the server is missing its encryption key. That is ours to fix, not yours. ## Choose what to send In the same card, under **Goals to send**, tick each goal you want and pick its Meta event: | Meta event | Use it for | |---|---| | `Purchase` | A paid order | | `Lead` | A form or a quote request | | `CompleteRegistration` | A signup | | `AddToCart` | An item added to the cart | | `InitiateCheckout` | The start of checkout | | `Subscribe` | A paid subscription or a newsletter | | `Contact` | A call, chat or email | | Custom | Any other name, letters and digits | Press **Save goals**. From then on, every match of the goal goes to Meta, from the browser and from the [Events API](https://sporetag.com/docs/events-api). ## What each event carries - `event_name`, `event_time` and `event_id`. - `action_source` set to `website`, and `event_source_url`: the page, without its query string. - `client_ip_address` and `client_user_agent` of the visitor. - `fbc`, from the `fbclid` on the landing page or Meta's `_fbc` cookie, and `fbp` from Meta's `_fbp` cookie, when present. - `em` and `ph`: email and phone, normalized and SHA-256 hashed, when you sent them with the Events API. - `external_id`: the SHA-256 hash of the visitor's first-party id, or of the `visitor.id` you sent. - `value`, `currency` and `order_id`, when the event has them. The raw email and phone never leave your server unhashed, and Sporetag never stores them. ## Count once with the pixel If your pages also run the Meta pixel, Meta would count the same sale twice. It counts once when both sides send the same event name and the same event id. Make the id in the page and give it to both: ```js const id = crypto.randomUUID(); fbq('track', 'Purchase', { value: 49, currency: 'USD' }, { eventID: id }); sporetag('Purchase', { event_id: id, value: 49, currency: 'USD' }); ``` From your server, send the same id as `event_id` in the Events API. An order id works well, such as `order-1042`, if the page uses it too. A goal on a page visit (such as `/thanks`) gets an id Sporetag makes up, which the pixel cannot know. Send that conversion from one side only. ## Refunds Meta has no documented way to change or take back a sale once it is sent, and no refund event. So a refund is not sent to Meta, and Meta's revenue still counts the refunded sale. Sporetag's own [revenue](https://sporetag.com/docs/revenue-and-mrr) takes refunds off. Google Ads and Microsoft Ads do take refunds: see [Refunds](https://sporetag.com/docs/send-results-to-ad-accounts#refunds). ## Test it 1. In Events Manager, open your pixel, then the **Test events** tab. 2. Copy the test event code, such as `TEST12345`. 3. Paste it into **Test event code** in Sporetag and save. 4. Trigger the goal on your site. It shows in Meta's Test events tab within a minute. While a test code is saved, Meta treats every event as a test. Remove the code when you are done. ## The delivery log **Delivery log** lists the last 100 sends, newest first, with Meta's answer for each one. **Failed** shows only those that did not get through. - Sends that fail for a passing reason (Meta busy, a network error) retry after 1, 2, 4, 8 minutes and so on, up to 6 hours apart, for 24 hours. Then they show as **Gave up**. - Sends Meta refuses for good (a bad field) show as **Failed**. - If Meta refuses the token, sends wait as **Waiting** until you save a new token. They then go out, if they are under 24 hours old. The log never shows the token, the IP address or any email or phone. ## Consent Sending the visitor's IP address, browser and click ids to Meta shares personal data with Meta. In the EU and UK this usually needs consent, whatever mode the site is in. With 90-day tracking and **Wait for consent** on, browser events go to Meta only after `sporetag('consent', true)`. See [Tracking modes](https://sporetag.com/docs/tracking-modes). A browser that sends [Global Privacy Control](https://globalprivacycontrol.org/) (`Sec-GPC: 1`) is never sent to Meta, with or without consent. California treats the signal as an opt-out of the sale and sharing of personal data. With 90-day tracking, the signal stays with the visitor's random id for 13 months, so later sales tied to it are not sent either. Your own statistics still count the visit. See [Send results to your ad accounts](https://sporetag.com/docs/send-results-to-ad-accounts#global-privacy-control). ## Match quality Meta matches better with more to go on. In Private mode, click ids live only for the visit, so a sale on a later day has no `fbclid`. Use [90-day tracking](https://sporetag.com/docs/tracking-modes) to keep click ids for 90 days, and send email or phone from your server with the [Events API](https://sporetag.com/docs/events-api). ## Google Ads Google Ads has its own row under [Send results to your ad accounts](https://sporetag.com/docs/send-results-to-ad-accounts) (when shipped). --- # Attribution report > See conversions and revenue by source, campaign, ad platform and short link, under six attribution models, with each customer's path. Source: https://sporetag.com/docs/attribution-report Section: Measure The attribution report answers one question: what brought the people who bought? It lists your conversions and revenue by where those people came from. Open a site, then the **Attribution** tab. It is on paid plans: Solo, Studio, Agency and Custom. Free does not include it. A conversion is any event or page visit that reaches one of the site's goals. Pick **All goals** or one goal, and a period of 7, 30 or 90 days. > The attribution report and 90-day tracking are on paid plans: Solo, Studio, Agency and Custom. Free does not include them. ## What it groups by | Group | Comes from | |---|---| | Source | The referrer, or `utm_source` when there is one | | Campaign | `utm_campaign` | | Ad platform | The click id on the landing page: `fbclid` for Meta, `gclid`, `gbraid` or `wbraid` for Google | | Short link | A click on one of your short links | The ad platform is **Meta ads** for `fbclid`, **Google Ads** for `gclid`, `gbraid` or `wbraid`, and **No ad click** otherwise. ## Attribution models Most people visit more than once before they buy. A model decides which visits get the credit. Pick one for the site under **Credit** at the top of the report. The dashboard's ad rows, client reports and the Assistant use the same one. The default is **Last touch**. | Model | Who gets the credit | |---|---| | Last touch | The latest visit before they converted gets all of it. | | First touch | Where they first came from gets all of it. | | Linear | Every visit gets an equal share. | | Position based | The first and last visits get 40% each. The visits between share 20%. | | Time decay | Visits closer to the conversion get more. Credit halves for every 7 days back. | | Any touch | Every visit gets full credit. Rows then add up to more than the total, and the report says so. | Each conversion's credit adds up to one conversion and its full value, except under Any touch. When two visits happen at the same moment, they share the credit equally. Spend and return use last touch when Any touch is picked, so ROAS never counts a sale twice. A direct visit (no referrer, campaign, click id or short link) never takes the credit from a known source. A server event that carries its own click id counts as a touch at that moment. ### Compare models **Compare models** shows conversions and revenue by source, campaign or ad platform under all six models side by side, with your model marked. When the columns agree, the choice of model does not matter much. When they differ, first touch usually shows what made people aware of you, and last touch shows what closed the sale. ### Customer journeys **Customer journeys** lists the most common paths to a conversion, such as "Meta ads, Email, Direct, Converted", with how many conversions took each path, the average days from the first visit and the average number of visits. Repeats in a row count once. A path with more than five steps shows the first step, a count of the hidden ones, then the last four. **Latest** shows the most recent conversions with their paths, and the person when they gave an email. ## How far back it reaches In Private mode a visitor is only known within one visit: the same daily hash on the same day. A sale tomorrow from today's ad click shows as Direct. In [90-day tracking](https://sporetag.com/docs/tracking-modes) a visitor is known for 90 days on your domain by the first-party id. The report can then link a sale today to a click weeks ago. Pick how far back it looks under **Look back**: 1, 7, 30 or 90 days. The default is 90. The report says which mode and window it is using. Server events join a visit when you send the visitor's IP and user agent (same day), or their first-party id as `visitor.id` (90-day tracking). See [Events API](https://sporetag.com/docs/events-api). ## Short link pages Each short link that points to one of your sites shows **Visits after**, the visits that arrived from the link, and **Conversions after**, the conversions credited to those visits under the site's model. ## Revenue Revenue comes from the `value` and `currency` you send with an event, from the browser or from the [Events API](https://sporetag.com/docs/events-api). It also comes from the [Stripe](https://sporetag.com/docs/stripe-connector) and [Shopify](https://sporetag.com/docs/shopify-connector) connectors. Their sales count as the `Purchase` event, on the date they happened. A sale sent both ways, with the same `event_id` or `order_id`, is counted once. With Stripe connected, **Revenue** beside **Conversions** at the top of the tab shows new revenue, MRR, lifetime value and refunds by source and campaign. See [Revenue and MRR](https://sporetag.com/docs/revenue-and-mrr). ## Ad spend Add your ad spend, and **Spend and return** shows spend, Sporetag revenue, return on ad spend (ROAS) and cost per purchase by platform, campaign, ad set and ad, with what the platform itself reports beside it. It follows the period, the goal and the site's model. - Meta Ads connects in one click. See [Meta ad spend and ROAS](https://sporetag.com/docs/meta-ads-spend). - Google Ads, TikTok, Microsoft and any other platform import spend from a file. See [Import ad spend from a file](https://sporetag.com/docs/csv-spend-import). Connecting Google Ads in one click is next (when shipped). Spend with no tracked visit shows as spend we could not match to tracked links, with a tip to fix it. This report keeps each currency on its own line; the dashboard adds them up in your reporting currency. ## What people told us When the site asks [How did you hear about us](https://sporetag.com/docs/how-did-you-hear), the report adds **What people told us**: each answer, how many people gave it and where Sporetag tracked them from. It says how many who answered came in as Direct, which is where word of mouth usually hides. The answers sit beside the tracked numbers and never change them. --- # Send results to your ad accounts > Send leads and sales to TikTok, Pinterest, Snapchat and Reddit, and to Google Ads, Microsoft Ads and LinkedIn (when shipped), so their bidding learns. Source: https://sporetag.com/docs/send-results-to-ad-accounts Section: Measure Ad platforms bid better when they know which clicks became customers. Sporetag sends your leads and sales to each ad account you turn on, from our server, so blockers and short cookie lives do not hide them. It is on paid plans: Solo, Studio, Agency and Custom. Meta has its own card: see [Meta Conversions API](https://sporetag.com/docs/meta-conversions-api). ## Turn a platform on Open your site's **Settings**, then **Integrations**, and find **Send results to your ad accounts**. Each platform is one row. - **TikTok, Pinterest, Snapchat and Reddit**: click **Connect**, paste the id and the access token from the platform's events manager (the page says where), then **Save and turn on**. - **Google Ads, Microsoft Ads and LinkedIn** (when shipped): connect the platform under **Ad spend** first, then click **Turn on**. Sporetag makes its own conversion actions in your account: "Sporetag lead", "Sporetag sale" and, for Google, "Sporetag closed deal". ## Pick what to send Under **What to send**, tick the goals. A goal named like a purchase goes as a sale, with its value; the rest go as leads. When one visit reaches two ticked goals, it goes once, as the sale. **Deals you win in your CRM** sends HubSpot and GoHighLevel deals marked won to Google Ads and Microsoft Ads, with the deal value, so bidding learns from closed business, not only form fills. Turn it off there if you would rather not. Live Stripe and Shopify sales on a ticked **Purchase** goal go too. ## Refunds When a sale you sent is refunded, in full or in part, from Stripe, Shopify or the [Events API](https://sporetag.com/docs/events-api), Sporetag tells each platform that has a way to hear it, so its revenue and return on ad spend stay true. **Refunds** under **What to send** is on by default. | Platform | What a refund does | |---|---| | Google Ads | The sale's value becomes what is left after every refund. Refunded in full, it is set to 0, which Google counts as taking the sale back. | | Microsoft Ads | The same: the new value, or the sale is retracted when refunded in full. | | Meta, TikTok, Pinterest, Snapchat, Reddit, LinkedIn | Nothing. None of them has a documented way to change a sale once it is sent. | A refund is sent once, even when Stripe tells Sporetag twice. Refunds go out for sales sent in the last 30 days, in the sale's own currency. The **Delivery log** lists each one beside its sale. A visitor who sent Global Privacy Control is never sent, refund or not. Google Ads conversions go through Google's Data Manager API. When Google Ads is switched on for Sporetag, sites that connected Google before need to **Reconnect** under **Ad spend** once, to allow it. ## How each conversion is matched | Platform | Matched by | |---|---| | Google Ads | gclid, gbraid or wbraid; or a hashed email or phone for leads without a click | | Microsoft Ads | msclkid, with a hashed email or phone when known | | TikTok | ttclid, hashed email and phone, the visitor id, IP address and browser | | Pinterest | the epik click id, hashed email and phone, IP address and browser | | Snapchat | the ScCid click id, hashed email and phone, IP address and browser | | Reddit | the rdt_cid click id, hashed email and phone, hashed IP address and browser | | LinkedIn | li_fat_id or a hashed email | Click ids last 90 days with [90-day tracking](https://sporetag.com/docs/tracking-modes), so a sale or won deal days after the click still names it. Emails and phones come from the [Events API](https://sporetag.com/docs/events-api), your store or your CRM, and leave Sporetag hashed with SHA-256. If nothing can be matched, nothing is sent. On a site that waits for consent, nothing goes until the visitor agreed. ## Global Privacy Control When a visitor's browser sends [Global Privacy Control](https://globalprivacycontrol.org/) (the `Sec-GPC: 1` header), Sporetag sends nothing about that visit to any ad platform: not to Meta, not to the platforms on this card. California treats the signal as a request to opt out of the sale and sharing of personal data, and sending conversions to ad platforms is sharing. With 90-day tracking, the signal is also kept with the visitor's random id for 13 months, so a later sale, won deal or Events API call tied to that id is not sent either, and ad click ids are not kept for them. Your own statistics still count the visit. The **Delivery log** says how many conversions were held back this way in the last 30 days. There is nothing to set up. ## Check it The row shows when it last sent and how many sends carried a click or contact details. **Delivery log** lists the last 100 sends with each platform's answer. Failed sends retry with growing gaps for 24 hours. If a platform refuses your token or login, the row says **Needs attention** and sends wait until you fix it. --- # How did you hear about us > Ask one optional question after a form or an order, and see the answers next to the source Sporetag tracked. Source: https://sporetag.com/docs/how-did-you-hear Section: Measure Some people find you through a friend, a podcast or a radio spot. No link is clicked, so they arrive as Direct. One short question catches them: "How did you hear about us?" The answers show next to the tracked source on the **Attribution** tab. It needs a paid plan and [90-day tracking](https://sporetag.com/docs/tracking-modes), so each person is asked once. ## Turn it on 1. Open your site, then **Settings**. 2. Find **How did you hear about us** and tick **Ask the question**. 3. Change the question or the choices if you like, one per line, up to 8. "Other" with a text box is added for you. 4. Click **Save question**. ## Where it is asked | Where | When | |---|---| | After a form | Someone sends a form with an email or phone field. A small card asks on that page, or on the next page within two minutes. | | Thank-you pages | The page address matches one you list, like `/thank-you` or `/order-received*`. `*` stands for any part. | | Your own form | Your form already has a field named like "how did you hear". Its answer is read and the card is not shown. | | Order emails | A link in your shop's order confirmation email opens a one-question page with your shop's name. | The card asks once per person, only after they agree to cookies when your site waits for consent. Closing it counts as an answer of nothing, so it does not come back. ## Shopify Shopify checkout pages do not run your tag, so the card cannot show on the Shopify thank-you page. Use the order email link instead: 1. In Sporetag, copy the **Link for your order email** from the question's settings. 2. In Shopify, open **Settings**, **Notifications**, **Order confirmation**, then **Edit code**. 3. Paste a line such as `How did you hear about us?` where you want it, with your link in place of LINK. 4. Save. The link carries the order number. Once the [Shopify connector](https://sporetag.com/docs/shopify-connector) syncs that order, the answer joins the customer and their tracked source. Asking on the Shopify thank-you page itself comes with the Sporetag Shopify app (when shipped). ## How answers are counted Answers are grouped, so "my neighbor" and "A friend or family" both count as **Friend or family**. The groups are Google, Facebook or Instagram, TikTok, YouTube, Friend or family, Local paper or radio, AI assistant, Podcast, Email and Other. Choices you add yourself keep their own row. **What people told us** on the Attribution tab shows each answer with where Sporetag first tracked those people from. The line on top says how many who answered came in as Direct. People can misremember, so the answers never change the tracked numbers or any model. They sit beside them. A person's answer also shows on their profile, and client reports can include a **What people told us** block. ## Privacy An answer is what the person picked or typed, up to 80 characters. It is never used to identify anyone. --- # Revenue and MRR > New revenue, MRR and what moved it, lifetime value by source and campaign, refunds and time to first payment, from Stripe, each with one plain sentence. Source: https://sporetag.com/docs/revenue-and-mrr Section: Measure The Revenue page shows what your Stripe customers paid and what brought them. Open a site, then **Attribution**, then **Revenue**. It needs the [Stripe connector](https://sporetag.com/docs/stripe-connector), on paid plans: Solo, Studio, Agency and Custom. Each part starts with one sentence that sums it up, such as "MRR grew $450 to $12,400: $900 new and $150 from upgrades, minus $600 canceled." The numbers under it show the detail. Pick a period: 30 days, 90 days or 12 months. Credit follows your site's attribution model, the same one the Conversions view uses, and changing it on either view changes both. See [Attribution report](https://sporetag.com/docs/attribution-report) for the models. Revenue keeps two touches per customer: the first and the last visit from a source. So: - **First touch** and **Last touch** credit that visit. Last touch is the last one before the payment. - **Linear** and **Position based** split credit evenly between the two. - **Time decay** gives more to the one closer to the payment, halving every 7 days. - **Any touch** gives both full credit, so rows add up to more than the total. A visit after a payment never takes credit for it. ## New revenue - **Revenue**: every payment in the period, renewals included. - **New revenue**: payments from customers whose first payment was in the period. - **New customers**: how many paid for the first time. Tables split revenue and new revenue by source, campaign, ad platform, ad (`utm_content`, which ad URL templates fill with the ad's name) and short link. ## MRR Monthly recurring revenue: what your active subscriptions bring in each month. - A yearly plan counts as a twelfth a month, a weekly plan as 52 weeks over 12 months, and a plan billed every 3 months as a third. Quantity counts. - A coupon that runs forever or for some months lowers MRR while it runs. A coupon used once does not. - A trial counts from the day it turns into a paid plan. - Past due subscriptions still count. Canceled, unpaid and paused ones do not. A subscription set to cancel at the end of its period counts until it ends. - Proration does not move MRR. An upgrade in the middle of a month bills the difference once, which shows as a payment, and MRR moves by the new plan's monthly worth. - Usage-based and tiered prices are left out, since their monthly amount is not known ahead. The page says how many subscriptions have one. What moved MRR in the period: | Move | What it is | |---|---| | New | A subscription started paying, or one that had stopped paid again | | Upgrades | A subscription moved to a higher monthly worth | | Downgrades | A subscription moved to a lower monthly worth | | Canceled | A subscription stopped paying | Each move ties to the customer, so the page shows MRR added and lost by source. MRR history starts with your first import, which reads every subscription Stripe has. Plan changes made before that are not in Stripe's records, so an older subscription counts at its current plan from the day it started. ## Lifetime value What each paying customer has paid so far, minus refunds, by first source and by campaign. Counted from 90 days before you connected Stripe. The sentence names the best source with 3 or more customers, so one big buyer does not decide it. ## Refunds The money refunded in the period, how many refunds, and the share of revenue. ## Time to first payment How long new customers took from their first visit to their first payment: the same day, 1 to 7 days, 8 to 30 days, or longer. Only customers seen on your site before they paid count here. ## Payments tied to visits The share of payments Sporetag could tie to a visit, and how: | How | What it means | |---|---| | Payment Link | The tag added the visitor's id to the link | | Checkout with the visitor id | Your code passed `client_reference_id` or `metadata.st_id` | | Stripe customer seen before | The same Stripe customer paid before, tied to a visit then | | Email given on the site | The payment's email is one the person gave on your site | | Matched after paying | The person was tied to a visit later | | Not seen on the site | No visit known yet | To tie more, see [Tie payments to visits](https://sporetag.com/docs/stripe-connector#tie-payments-to-visits). ## Money in more than one currency Money adds up in your reporting currency (**Settings**, **Reporting currency**), else the currency with the most revenue. Payments in other currencies are converted at the European Central Bank rate for the day they were paid, and each MRR change at the rate for the day it happened, so past MRR never moves with exchange rates. The **ECB rates** tip under the numbers names what was converted. See [Profit, blended ROAS and currencies](https://sporetag.com/docs/profit-and-currency). ## On the dashboard and in client reports Add **Revenue and MRR from Stripe** to a [dashboard](https://sporetag.com/docs/client-dashboards) in edit mode, then pick its view: new revenue, MRR, lifetime value, refunds, time to first payment or payments tied to visits. Add one per view you want. Each leads with the same plain sentence. [Client reports](https://sporetag.com/docs/client-reports) take the same blocks. The **Revenue and MRR** template has new revenue, MRR, lifetime value, refunds and time to first payment, sent monthly. --- # Profit, blended ROAS and currencies > What every dollar on ads brought in sales, profit from the costs you give, and money in one currency at the European Central Bank's daily rate. Source: https://sporetag.com/docs/profit-and-currency Section: Measure With a store and ad spend connected, the dashboard shows **Return on all ad spend**: one sentence, such as "Every $1 on ads brought $4.20 in sales last month, up from $3.80 the month before.", then the numbers behind it. Add your costs, and it shows profit too. It needs [Stripe](https://sporetag.com/docs/stripe-connector) or [Shopify](https://sporetag.com/docs/shopify-connector), plus [Meta Ads](https://sporetag.com/docs/meta-ads-spend), another ad platform or a [spend file](https://sporetag.com/docs/csv-spend-import), on paid plans: Solo, Studio, Agency and Custom. ## Blended ROAS Blended ROAS is every sale from your store divided by every ad platform's spend, for the period. Some tools call it MER (marketing efficiency ratio). It is the same number. - **Sales** are orders and renewals from Stripe and Shopify, before refunds: the same as the Sales card. - **Ad spend** is every platform you connected or imported, added up. - It counts every sale, whether or not Sporetag tied it to an ad. The ROAS on the [ad spend panel](https://sporetag.com/docs/attribution-report) counts only sales from tracked ad visits. Blended ROAS is the one that still works when tracking misses some sales. - **Ads cost** is the same comparison the other way round, as a share of sales: $1,000 of spend on $4,200 of sales is 23.8%. With no ad spend in the period, there is nothing to divide by, and the panel says so. ## Profit Profit shows only once you say what things cost. Sporetag never guesses a cost. 1. Open the site, then **Settings**, then **Profit**. 2. Type your **cost of goods** as a percent of sales, such as 40. 3. Optional: type your **fixed costs a month**, such as rent, salaries and software, and pick their currency. 4. Click **Save costs**. The panel then shows: | Number | What it is | |---|---| | Gross profit | Sales, minus refunds, minus cost of goods | | Net profit | Gross profit minus ad spend, and minus fixed costs when you set them | | Break-even ROAS | The blended ROAS where ads pay for themselves: 1 divided by your gross margin. At 40% cost of goods, it is 1.67x | Fixed costs are spread over each day of their month, so a 7-day period carries 7 days of them. ### Product costs from Shopify When your Shopify app can read products or inventory (the `read_products` or `read_inventory` scope), Sporetag reads each product's cost from Shopify and keeps what each order's products cost. Orders with a cost for every product use it. The percent covers the rest. - Shopify keeps only today's cost. An order Sporetag reads later uses the cost at that time. - If some orders have product costs and you set no percent, profit is not shown, rather than counting the rest as free. Add a percent to fix it. - Added the scope after connecting? Paste the app details again on the Shopify connector page, so Sporetag sees it. ## One currency Sporetag adds money up in one currency. Pick it in **Settings**, **Reporting currency**. On **Automatic**, it is the currency most of each site's sales are in. Sales, refunds, ad spend and MRR in other currencies are converted at the European Central Bank's euro reference rate: - Each sale at the rate for the day it was paid, and each day of ad spend at that day's rate. - Each change in MRR at the rate for the day it happened, so past MRR does not move when rates do. - A weekend or bank holiday uses the last rate before it. - The ECB publishes rates for about 30 currencies, around 4 PM in Frankfurt on working days. Money in a currency it does not quote stays out of the totals, and the panel says **Some currencies left out**. Converted numbers carry an **ECB rates** tip with the original amounts, such as "Includes 1,240 EUR and 300 GBP, converted to USD at the European Central Bank rate for each day." Emailed reports print the same line. The ECB publishes these rates for information. They are right for reporting, not for accounting or tax. ### Where money is converted | Where | Currency | |---|---| | Dashboard, client dashboards and client reports | Your reporting currency | | [Revenue and MRR](https://sporetag.com/docs/revenue-and-mrr) | Your reporting currency | | [Attribution report](https://sporetag.com/docs/attribution-report) | Each currency on its own line | | [Read API](https://sporetag.com/docs/api) | Each currency on its own, as sent | ## Common questions ### Why is my blended ROAS higher than my ad ROAS? Blended ROAS counts every sale, including people who came back by email, search or word of mouth. Ad ROAS counts only sales from tracked ad visits. The gap between them is roughly what your ads bring that tracking cannot see, plus what would have sold anyway. ### What is a good break-even ROAS? It depends on your margin. At 30% cost of goods, ads break even at 1.43x. At 60%, they need 2.5x. Blended ROAS above break-even means ads pay for themselves, before fixed costs. --- # Profiles > One page per visitor and customer with every click, visit, email, text and sale, their first and last source, and lifetime value. Needs 90-day tracking. Source: https://sporetag.com/docs/customer-profiles Section: Measure Profiles show each person who visits, signs up or buys, one page each. You see every visit, short link click, email or text click, event and sale over time. You also see their first and last source, their orders and what they spent in total (lifetime value). Each profile has a **stage** (Lead, Engaged, Customer and so on) and one conversation stream: every email and text sent and received, and every visit, goal, form, order and CRM stage, in time order. A box at the bottom lets you write to them. See [Messages](https://sporetag.com/docs/messages). Open a site, then the **Profiles** tab. Profiles are on paid plans: Solo, Studio, Agency and Custom. Free does not include them. ## Visitors before they give an email With 90-day tracking, every visitor gets an anonymous profile on their first visit, named like **Visitor 4F2A9C** from their device id. It shows when they were first and last seen, their visits, the page they landed on, their first and latest source (with the ad platform when an ad click id came with them), country, device and browser, and the same journey as a customer: visits, pages, goals and events. - With **Wait for consent** on, a visitor gets a profile only after they agree. - When the visitor gives an email (a form, the identify call, a checkout), that profile becomes the customer. Nothing is copied or doubled: it is the same profile, now with their email and name. If the email already belongs to a customer, the visits join that customer. - An anonymous profile is deleted 90 days after the last visit, when the device id runs out too. - Each site keeps up to 25,000 anonymous profiles on Solo, 50,000 on Studio and 100,000 on Agency and Custom. Past that, the visitor seen longest ago makes room for each new one, so recent visitors always have a profile. Everyone still counts in your stats and still becomes a customer when they give an email. - In Private mode there are no visitor profiles. Private mode keeps no id from one day to the next, by design. On the Profiles tab, **All** lists everyone, anonymous visitors too, and **With email** lists only customers: people who gave an email or another id. Each shows its count. The tab opens on **All**. ### Visits but no profiles? 90-day tracking needs its own tag, the one that loads `sa.js`. The plain tag (`s.js`) still counts visits, but keeps no id, so no one gets a profile and sales tie back only within the same day. When a site with 90-day tracking has sent visits from the plain tag in the last 24 hours, and none from the 90-day tag, the dashboard, the Profiles tab and the **Tracking mode** card in **Settings** say so and show the tag to paste instead. If your site asks for consent itself and loads the tag only after the visitor agrees, you can leave **Wait for consent** off. ## What you need 1. **90-day tracking** on the site. Profiles build on its first-party id (the `_st_id` cookie), which ties one person's visits together for 90 days. Switch it in the site's **Settings** tab. See [Tracking modes](https://sporetag.com/docs/tracking-modes). 2. **Consent, where the law asks.** 90-day tracking stores an id on the device. In the EU and UK this usually needs consent first. Turn on **Wait for consent**, and nothing is stored or identified until your banner says yes. Sporetag has a [simple cookie banner](https://sporetag.com/docs/cookie-banner) you can turn on with no code. 3. **Nothing else, for most sites.** The tag you added in setup already adds people who sign up, sign in or send a form. The Profiles tab shows it under **How people are added**. ## How people are added New people arrive on their own. No importing again. - **Synced from your tag.** On a new site, the one tag line adds people from sign-up, sign-in and other forms on your site. The card says how many it added this week. Details below. - **Shopify.** Connect it under **Integrations**. It adds every buyer from their order, and every new customer account, with their email, phone and name. Nothing to add to your theme for this. - **Stripe, Klaviyo or Mailchimp.** Connect them under **Integrations**. Each brings in its customers or subscribers, and keeps doing so. - **Sign-ins with no form**, like Sign in with Google, Sign in with Apple or a magic link. Your site never shows a form, so the tag has nothing to read. Add one more line, called right after sign-in. The install step in setup offers it under **Signs people in with Google or a magic link? Add one more line**, and the Profiles card links there. See [Identify on your site](#identify-on-your-site). **Import a list once** sits under the card as a quiet link: a one-time catch-up for people who have not visited lately. See [Import customers](https://sporetag.com/docs/import-customers). When nothing automatic is on, the card also shows the identify line and server code under **For developers**. ## People from sign-ups and forms The switch is **Add people from sign-ups and forms**, on the Profiles tab. New sites start with it on. Sites added earlier start with it off; one tap turns it on. Turn it off any time. Your privacy policy should say that your site's forms send the email and name to an analytics service. When a visitor sends a form on your site that has an email or phone field: - Sporetag adds them as a customer with the email, and the phone and name if the form has fields for them. Their earlier visits join the profile. - Sign-up and sign-in forms count. An email typed in a username or login field counts too. A username that is not an email is skipped. - Forms sent by script, as in many single-page apps, count too. When the page sends the form itself and no submit event fires, a press of the form's submit button counts instead, once. A form the browser would refuse, for example with a required field empty, is not counted. - It sends a `Form sent` event, which the **Someone fills in a form** goal counts. What it never does: - It never reads password fields. A field of type password, or named like a password, card number, security code, IBAN, social security number, secret or token, is skipped before its value is read. Hidden and file fields are skipped too. - It never reads the rest of the form, only fields that look like an email, a phone or a name. - It never sends anything in Private mode, and never before the visitor agrees when **Wait for consent** is on. Press **Test it**, send a form on your site with your own email, then **Check again**. The panel shows the page and the fields it found, never the values. ## Identify on your site For sign-ins with no form on your site (Google, Apple, magic links), or to send your own user id. Right after someone signs in, tell Sporetag who this is: ```js window.sporetag?.('identify', { email: user.email, name: user.name, id: user.id }); ``` You can send `email`, `phone`, `name` and `id` (your own user id). Send at least one of email, phone or id. The `?.` makes the line safe on pages where the tag is not loaded: it then does nothing. - It works only with 90-day tracking, and only after consent when you wait for it. In Private mode the call does nothing and sends nothing. - Earlier visits from the same device join the profile. So the ad or short link that first brought them in becomes their first touch. - The same email from a phone and a laptop is one customer. ## Identify from your server Events you send with the [Events API](https://sporetag.com/docs/events-api) identify the customer too, when the site uses 90-day tracking. Send any of `email`, `phone`, `visitor.id` (the `_st_id` cookie) or `external_ids`: ```js body: JSON.stringify({ name: 'Purchase', event_id: 'order-1042', value: 49, currency: 'USD', email: order.email, visitor: { id: req.cookies._st_id }, external_ids: { stripe_customer: order.customer }, }), ``` A sale with a `value` adds an order and its value to the customer. Revenue adds up in the customer's first currency. ### Shopify and Stripe The easiest way: connect [Stripe](https://sporetag.com/docs/stripe-connector) or [Shopify](https://sporetag.com/docs/shopify-connector) on the site's **Integrations** page (under **Settings**). Orders, refunds and subscriptions then join each customer on their own, with the last 90 days imported. To send them yourself instead: ### Shopify checkout Send `orders/paid` webhooks to the Events API with the order email, as in [From a Shopify webhook](https://sporetag.com/docs/events-api#from-a-shopify-webhook). Add `external_ids: { shopify_customer: String(o.customer.id) }`. ### Stripe Send `checkout.session.completed` to the Events API, as in [From a Stripe webhook](https://sporetag.com/docs/events-api#from-a-stripe-webhook). Copy `_st_id` into `metadata.st_id` when you create the session, and send it back as `visitor.id`. ## The customer page - **Lifetime value**, **orders**, **first seen** and **last seen**. - **First touch** and **last touch**: the source, campaign, ad platform and short link of their first and latest known visit. A direct visit never replaces a known one. - **Journey**: one list, newest first. Visits with their source, short link clicks, email and text clicks (visits tagged `utm_medium=email` or `sms`), custom events, server events, purchases with their value, and sends to Meta. Items from other tools show here too. Filter by source or by kind. - **Seen on**: countries and devices, and what the person is known by. - **Messages and flows**: whether they agreed to texts or unsubscribed from email, where that answer came from (a website form, an import, the unsubscribe link, a STOP reply) and when, the tags [automations](https://sporetag.com/docs/automations) gave them, and each flow they are in or went through, with a link to it. Visits and events are kept in detail for about 90 days. After that the journey shows less. The first touch, orders and revenue stay on the profile for as long as the customer does. The page says so when it applies. ## The list Search by email, name or phone, or by a visitor's name such as `Visitor 4F2A9C`. Sort by last seen, revenue or first seen. **Came from** shows where each person came from: your site, a website form, an import, Stripe, Shopify and so on. Filter by whether they have an email, where they came from (pick **Imported lists** for imports), and by source, ad platform, campaign or short link, for the first touch or the last touch. **Export CSV** downloads the list as it is filtered. The customer page has a **Contact** card with the email, phone and name, and **Details** with any extra columns from an import. The [attribution report](https://sporetag.com/docs/attribution-report) counts customers per source and splits them into new and returning. Each count links to the customers behind it. ## Matching and merging A customer can be known by many things: an email, a phone number, a device id, your user id, and ids in other tools such as a Stripe customer id. When one call shows that two profiles are the same person, they merge into one. The page lists each merge and why. Two different emails are never merged. If two people share a device, the device moves to whoever identified last. ## Privacy - Emails and phone numbers are normalized and hashed with SHA-256, the way Meta asks. People are matched on the hashes. - **Show contact details** (on by default) keeps the email, name and phone number, and details from an import, encrypted, so you can see who is who. Turn it off under **Privacy and data requests** on the Profiles tab. They are then deleted, and people show as a masked label such as `a•••@g•••.com`. While it is off, only hashes are kept. - Emails, phones, names and details never go into your stats. Events carry only the random device id and a random customer id. - Anonymous visitor profiles hold no email, phone, name or IP address: only the random device id, dates, counts, the landing page, sources, country, device and browser. ### Delete a customer or visitor Open the profile, then **Delete this customer** (or **Delete this visitor**). The profile, its ids and its items are deleted. Its ids are never linked again on this site. Visits and events already recorded cannot be edited; they age out within about 90 days. ### Forget this email For a data request, use **Forget this email** under **Privacy and data requests**. It deletes the customer with that email, if there is one, and never links that email again on this site. --- # Import customers > Bring in contacts from Klaviyo, Mailchimp, Shopify or a spreadsheet as a CSV file. Match the columns, then people are added or updated, never doubled. Source: https://sporetag.com/docs/import-customers Section: Measure Import a list of people from any tool: an export from your email tool, Klaviyo, Mailchimp or Shopify, or a spreadsheet saved as CSV. Each person gets a [customer profile](https://sporetag.com/docs/customer-profiles), and someone who is already there is updated, not added twice. People who unsubscribed stay unsubscribed. An import is a one-time catch-up. From then on, new people arrive on their own, without importing again: the ways are under **How people are added** on the Profiles tab: your tag (sign-ups, sign-ins and forms), Shopify, Stripe, Klaviyo or Mailchimp. Import is on paid plans: Solo, Studio, Agency and Custom. Free does not include it. ## Import a list 1. Open the site, then **Profiles**, then **Import** (or **Import a list**). 2. **Choose a list.** Drop the CSV file on the box, pick it, or paste the rows. The first line must name the columns, like `Email, First name, Phone`. Commas, semicolons and tabs all work. 3. **Match columns.** Sporetag guesses what each column holds. Check each one and change it if needed. The first 3 rows show below, as they will be read. 4. If the list has no email status column, answer **Did these people agree to hear from you by email?** It starts on **No, or not sure**. **Yes** notes their consent on each profile, with the date and the file. **No** means they get no marketing email until they opt in (see below). 5. Tick the box to confirm these people gave you their details and you may use them. 6. Press **Import**. Keep the page open until it says **Import done**. If you close it, open it again from **Recent imports** and it carries on where it stopped. ## Columns | Pick | Means | |---|---| | Email | The email address. Used to match people | | Phone | The phone number, with the country code if you have it. Used to match people | | First name, Last name | Joined into one name | | Full name | The whole name in one column | | Id in your other tool | Their id in the tool you exported from. Used to match the same list next time | | Email status | Whether they may get email. Subscribed, confirmed, opted in or yes notes their consent. Unsubscribed, bounced, cleaned, complained, spam or no marks them unsubscribed. Anything else, such as never subscribed, pending or blank, means they did not agree. A column named **Unsubscribed** or **Opted out** reads yes and no the other way round | | Date they joined | When they joined the other tool, like `created_at` or **Date added**. It becomes their first seen date when it is earlier | | Tags | Words split by commas, like `vip, spring-sale`. Each becomes a tag on the profile, up to 10 | | Custom property | Shown on the customer page under **Details**, named after the column | | Do not import | Left out | You need at least one of Email, Phone or Id. A column named like a password, card number or secret is never imported. ## Matching Sporetag matches each row the same way it matches people from your site and your connected tools: - The same email, in any case, is the same person. So is the same phone number. - A row that matches someone already here updates them: a new name, phone or detail is added, and a property with the same name is replaced. - Two rows for the same person in one file become one customer. - When a row shows that two existing records are one person, they merge. The customer page says why. - An email you were asked to forget (**Forget this email**) is never added back. - Someone who unsubscribed here, by a link or a reply, stays unsubscribed even if the list says subscribed. ## Unsubscribed people A row whose email status says unsubscribed, bounced or complained is still imported, so their history stays in one place. Their profile shows the email as unsubscribed, and the address goes on the site's do-not-email list. Automations and messages never email them. ## People who did not agree When you answer **No, or not sure**, or a row's status is not subscribed, each new person's profile shows the email as **Not agreed**. Flows, one-off messages and campaigns skip them, until they opt in: - They give their email on a form on your site. - A later import marks them subscribed. If they write to you, you can still reply from **Messages**. People who were already here before the import keep what they had. Imported people show **Import** under **Came from** on the list. Filter by **Came from**, then **Imported lists**, to see only them. ## The summary When it is done you see how many people were **added**, **merged** with someone already here, came in **unsubscribed**, and were **skipped**, and how many never agreed to email, and why rows were skipped. **See who was imported** opens the list with only them: | Reason | Means | |---|---| | No email, phone or id | The row had nothing to match on | | Email is not valid | The email could not be read, and there was no phone or id | | Id has spaces or symbols | Ids may use letters, digits and `. _ - : ~ @ +` | | Asked to be forgotten | The email or phone was forgotten on this site | The first skipped row numbers are listed. Row 1 is the header. ## Limits - Up to 10,000 rows and 2 MB per file, and up to 50 columns. Split a bigger list into several files. - Up to 10 imports per site per day. - Up to 30 custom properties per person, each up to 200 characters. ## Privacy - While the import runs, its rows wait encrypted, bound to your site, with only the columns you kept. Each part is deleted as soon as it is imported. Anything left after a day is deleted. - Emails, phones, names and properties are kept encrypted, and only while **Show contact details** is on. With it off, only hashed emails and phones are kept. See [Profiles](https://sporetag.com/docs/customer-profiles#privacy). - Imported details never go into your stats or to Meta. - Import only people who gave you their details. Name Sporetag in your privacy policy. --- # Cohorts and lifetime value > See how many visitors come back, grouped by the week or month they first came and by their first source, and what customers from each source spend. Source: https://sporetag.com/docs/cohorts Section: Measure Cohorts answer two questions: do people come back, and which sources bring the customers worth the most. Open the site, then **Profiles**, then **Cohorts**. Cohorts are on Solo, Studio and Agency. ## Who comes back Each row is everyone whose first visit fell in one week (or month, with **Monthly**). The columns are the weeks after: **Week 1** is the share who visited again the next week, **Week 2** the week after that, and so on. Darker cells mean more came back. Weeks that have not begun for a row stay empty. The sentence on top gives the average return rate for the next week (or month), from cohorts whose next week has ended. **Who comes back, by first source** groups the same people by where they first came from. Each column counts only the people whose week has begun, so a new source is never marked down for weeks it has not had. Once two sources have 10 visitors or more, the sentence on top names the one whose visitors come back most. Return visits need [90-day tracking](https://sporetag.com/docs/tracking-modes), which keeps a first-party id so the same person is known across days. Weeks start on Monday and use your site's time zone. Anonymous profiles are deleted 90 days after their last visit, but their first visit stays in the cohort, so return rates never rise because the people who never came back were removed. ## Lifetime value The table lists customers with an email who bought, by first source or by first campaign: | Column | Means | |---|---| | Customers | People from that source who bought at least once | | Per customer | Revenue to date, divided by those customers | | Bought again | The share who bought more than once | | First 30, 90 and 365 days | Revenue per customer in their first days, counted from their first visit | | Revenue | All their revenue to date | The day columns show when a store is connected, since synced orders say when each sale happened. They count only customers first seen at least that many days ago, so new customers never pull a column down. Refunds come off. Money is shown in the currency most of your customers pay in. Customers who pay in another currency are counted in one line under the table, never converted. The sentence on top names the source (or campaign) whose customers spend the most each, once two of them have 3 customers or more. --- # Bring your data together > One stream per customer from your site, your server and your other tools. What is automatic, what goes back to your tools, and how to send from any tool. Source: https://sporetag.com/docs/bring-your-data-together Section: Measure Your customers leave a trail in many tools: your site, your store, your email and text tools, your CRM, your phone. Sporetag puts it in one place. Each [customer profile](https://sporetag.com/docs/customer-profiles) has one stream, in time order, with every item labeled by where it came from. Customer profiles are on paid plans: Solo, Studio, Agency and Custom, with the site in [90-day tracking](https://sporetag.com/docs/tracking-modes). ## What is automatic today | From | What shows up | |---|---| | Your site (the Sporetag script) | Visits with their source, short link clicks, email and text clicks, custom events, purchases | | Your server ([Events API](https://sporetag.com/docs/events-api)) | Server events and purchases, with value | | [Stripe](https://sporetag.com/docs/stripe-connector) | Payments, refunds, and subscriptions started, renewed, changed and canceled | | [Shopify](https://sporetag.com/docs/shopify-connector) | Orders, refunds and new customers, with the UTMs Shopify kept | | [Klaviyo](https://sporetag.com/docs/klaviyo-connector) | Email and text sends, opens, clicks and unsubscribes | | [Mailchimp](https://sporetag.com/docs/mailchimp-connector) | Campaign sends, opens, clicks and unsubscribes | | [Attentive](https://sporetag.com/docs/attentive-connector) | Text and email sends, opens, clicks and unsubscribes, by webhook from the day you turn it on | | Meta Conversions API | Each send to Meta and its status | | [Meta Ads](https://sporetag.com/docs/meta-ads-spend) | Daily spend by campaign, ad set and ad, with Meta's own purchase counts | | [Spend files](https://sporetag.com/docs/csv-spend-import) | Daily spend from Google Ads, TikTok, Microsoft, LinkedIn or any platform | All connectors connect from the site's **Integrations** page (under **Settings**). Stripe, Shopify, Klaviyo and Mailchimp import the last 90 days, then keep up on their own. A sale that also came in from your site or the Events API is counted once, and shows once on the customer's timeline with both sources. ## What goes back out Klaviyo, Mailchimp and Attentive also get data back from Sporetag, for people they already have: each customer's first and last source, lifetime value, orders and [best send hour](https://sporetag.com/docs/segments-and-best-send-time), and the [segments](https://sporetag.com/docs/segments-and-best-send-time) you pick. Your tool can then send to the right people at the right hour. ## Send data from any tool Any tool that can call a webhook can add to the stream today. Send it to the Events API with two extra fields: - `kind`: what happened. One of `email_sent`, `email_opened`, `email_clicked`, `email_unsubscribed`, `sms_sent`, `sms_clicked`, `sms_unsubscribed`, `form`, `call`, `note`, `order`, `refund`, `subscription_started`, `subscription_renewed`, `subscription_changed` or `subscription_canceled`. - `source`: the tool, in lowercase, such as `klaviyo`, `mailchimp`, `attentive`, `postscript`, `hubspot` or `my_crm`. Say who it is with `email`, `phone`, `visitor.id` or `external_ids`. Put short details in `payload`. ```json { "name": "October letter", "kind": "email_opened", "source": "klaviyo", "event_id": "klaviyo-open-81723", "email": "ann@example.com", "payload": { "campaign": "october-letter" } } ``` - `order` counts like any purchase: it reaches goals, the attribution report and Meta. - Every other kind is added to the customer's stream only. It does not count toward your plan's events or your goals. - `refund` with a `value` lowers the customer's revenue. - `event_id` keeps a retried webhook from being added twice. - `payload` takes up to 12 short text or number values. Anything that looks like an email or phone number is dropped. ### External ids `external_ids` ties ids from other tools to the customer, so the next item can use them alone: ```json "external_ids": { "stripe_customer": "cus_Q8x2", "hubspot_contact": "5012" } ``` Names are lowercase with underscores. Up to 10 per event. ### Zapier 1. Make a Zap with the trigger from your tool, such as "New Open" in your email tool. 2. Add the action **Webhooks by Zapier**, then **POST**. 3. URL: `https://sporetag.com/api/v1/events`. Payload type: `json`. 4. Data: `name`, `kind`, `source`, `email` and `event_id`, mapped from the trigger. 5. Headers: `Authorization` with `Bearer ` and your site's secret key. ### Make 1. Add the **HTTP** module, **Make a request**. 2. URL `https://sporetag.com/api/v1/events`, method `POST`. 3. Header `Authorization: Bearer st_sk_...`. Body type **Raw**, content type **JSON**. 4. Write the JSON body as in the example above, with values from the earlier modules. Keep the secret key in the tool's own settings. Never put it in a page. ## Native connectors Live now: [Stripe](https://sporetag.com/docs/stripe-connector), [Shopify](https://sporetag.com/docs/shopify-connector), [Klaviyo](https://sporetag.com/docs/klaviyo-connector), [Mailchimp](https://sporetag.com/docs/mailchimp-connector), [Attentive](https://sporetag.com/docs/attentive-connector) and [Meta Ads spend](https://sporetag.com/docs/meta-ads-spend). Spend from any other ad platform comes in [from a file](https://sporetag.com/docs/csv-spend-import). Ad spend joins your sales on the Attribution tab, not the customer stream: it belongs to campaigns, not people. Postscript limits its API to partners, so it has no connector yet (when shipped). [What works today](https://sporetag.com/docs/postscript-connector). Next (when shipped): Google Ads spend in one click, then CRMs such as HubSpot and GoHighLevel, call tracking and form tools. Until then, the Events API above covers any of them that can send a webhook. --- # Stripe connector > Connect Stripe with a read-only key. Payments, refunds and subscriptions tie to the visits, ads and links that brought each customer, with MRR kept current. Source: https://sporetag.com/docs/stripe-connector Section: Measure The Stripe connector reads your payments, refunds and subscriptions. Each one ties to the customer who paid, and to the visits, ads and short links that brought them. You see it on the [Revenue page](https://sporetag.com/docs/revenue-and-mrr), on each [customer profile](https://sporetag.com/docs/customer-profiles), in the [attribution report](https://sporetag.com/docs/attribution-report), and live sales go to your ad accounts. It is on paid plans: Solo, Studio, Agency and Custom. Free does not include it. **Connect with Stripe (when shipped).** A one-click login: click **Connect**, log in to Stripe in the new tab and allow read access, and you are done, with no key to paste. Until it is switched on, use the steps below. Sporetag only reads. The key you give it cannot charge, refund or change anything in Stripe. ## Connect 1. In Sporetag, open your site, then **Settings**, then **Integrations**. Next to **Stripe**, click **Connect**. 2. In Stripe, open [API keys](https://dashboard.stripe.com/apikeys) and click **Create restricted key**. If Stripe asks how you will use the key, pick the option for another app or website. 3. Name it `Sporetag`. Set these to **Read** and leave everything else at **None**: - Customers - Charges - PaymentIntents - Checkout Sessions - Invoices - Refunds - Subscriptions 4. Click **Create key**. Stripe may ask for a code it sends you. Copy the key. It starts with `rk_live_`. 5. Paste it into Sporetag and click **Connect Stripe**. Sporetag checks that the key can read each of the seven. If one is missing, it says which one. Use a test key (`rk_test_`) to try it with test data first. Do not paste your secret key (`sk_live_`). It can do anything in your account, so Sporetag refuses it. ## What happens next - **The first import** reads the last 90 days of payments and refunds, and every subscription you have, whatever its age, so MRR starts right. A busy account can take a few hours, since each run reads a small batch. Integrations shows **Importing** and a count. - **After that**, Sporetag checks for new payments and plan changes every 15 minutes. - **Sync now** starts a check at once. The key is stored encrypted. It is never shown again, and it never appears in logs. ## Tie payments to visits A payment ties to the visits before it when Stripe knows the visitor's id. This needs the site in [90-day tracking](https://sporetag.com/docs/tracking-modes). **Payment Links, Buy Buttons and pricing tables: nothing to do.** Once Stripe is connected, the Sporetag tag adds the visitor's id to every `buy.stripe.com` link on your pages as `client_reference_id`, and sets `client-reference-id` on Stripe Buy Buttons and pricing tables. It never replaces an id you set yourself, and on a site that waits for consent it waits too. Stripe reads the Buy Button and pricing table attribute when they first draw, so keep the Sporetag tag above Stripe's script on the page. **Checkout from your own code: one line.** Where you create the Checkout Session, pass the `_st_id` cookie: ```js const session = await stripe.checkout.sessions.create({ // ...your line items, mode and URLs client_reference_id: req.cookies._st_id, }); ``` `metadata: { st_id: req.cookies._st_id }` works too, on a Checkout Session, a PaymentIntent or a subscription. Sporetag only takes an id that looks like one of its own (32 letters and numbers), so a `client_reference_id` you use for your own order numbers is left alone. **Without the id**, Sporetag still ties a payment when: - the Stripe customer paid before and was tied to a visit then, or - the email on the payment is one the person gave on your site, in a form Sporetag reads or through `sporetag('identify', ...)`. The Revenue page says how many payments are tied, and how. A payment that is not tied still counts in revenue and MRR, under Direct. ## Instant updates (optional) Without a webhook, new sales and plan changes show up within 15 minutes. With one, they show up in seconds, and a live sale goes to your ad accounts right away. 1. Open the Stripe connector's page in Sporetag (**Settings** next to Stripe). Copy the **Endpoint URL**. It looks like `https://sporetag.com/hooks/stripe/...`. 2. In Stripe, open [Webhooks](https://dashboard.stripe.com/webhooks) and add an endpoint. Stripe may call it an event destination. 3. Pick these events: - `checkout.session.completed` - `charge.succeeded` - `charge.refunded` - `invoice.paid` - `customer.subscription.created` - `customer.subscription.updated` - `customer.subscription.deleted` 4. Paste the endpoint URL and save. 5. Reveal the endpoint's **Signing secret** (it starts with `whsec_`), copy it, and paste it into Sporetag under **Instant updates**. Set up before `customer.subscription.updated` was on this list? Add it to your endpoint in Stripe. Until you do, upgrades and downgrades show up with the 15-minute check. Sporetag checks the signature on every webhook and refuses any that do not match. It then reads the object again from Stripe with your key, so it never trusts the webhook body alone. Each event is handled once: when Stripe sends the same event id again, Sporetag answers and changes nothing. ## What shows up on a customer | Stripe | On the customer | |---|---| | A paid Checkout Session | **Order**, with the amount and product names | | A paid invoice | **Order**, or **Subscription renewed** for a renewal | | A payment with no session or invoice | **Order** | | A refund | **Refund**, which lowers revenue | | A new subscription | **Subscription started**, with the plan | | An upgrade or downgrade | **Plan changed**, with the change to MRR | | A canceled subscription | **Subscription canceled** | One payment is one order. A Checkout Session, its PaymentIntent, its charge and its invoice are linked, so Stripe telling us about each of them never counts the sale twice. Orders and revenue add up into the customer's lifetime value. Revenue adds up in the customer's first currency. ## Who the customer is Sporetag finds the customer by: - the Stripe customer id, - the email and phone on the payment (hashed with SHA-256, the way Meta asks), - the visitor's id, from `client_reference_id` or `metadata.st_id`. ## Goals, Meta and your ad accounts Synced sales count as the **Purchase** event. They reach any goal on the event `Purchase`. A new sale goes once to [Meta](https://sporetag.com/docs/meta-conversions-api) when that goal sends to Meta, and once to each ad account turned on under [Send results to your ad accounts](https://sporetag.com/docs/send-results-to-ad-accounts) when that goal is ticked there: - Only live sales: ones that happened in the last 24 hours. The 90-day import never sends old sales. - Renewals are not sent. They are not new buyers. - The hashed email and phone go along, and the ad click ids (such as `gclid` or `ttclid`) from any visit tied to the buyer, so the platform can match the sale to its click. - A refund of a sale that was sent lowers its value in Google Ads and Microsoft Ads. See [Refunds](https://sporetag.com/docs/send-results-to-ad-accounts#refunds). - A sale the browser or the Events API already sent under the same id is not sent again, and the other way round. ### The event_id rule Meta, the other platforms and Sporetag all count a sale once per `event_id`. The Stripe connector uses the Stripe object id: | Sale | event_id | |---|---| | Stripe Checkout | The Checkout Session id, `cs_...` | | A paid invoice | The invoice id, `in_...` | | Any other payment | The PaymentIntent id, `pi_...` | If you also send the sale from the browser or the [Events API](https://sporetag.com/docs/events-api), use the same id as `event_id`. For Checkout, your success page gets the session id when the success URL has `?session_id={CHECKOUT_SESSION_ID}`: ```js sporetag('Purchase', { event_id: sessionId, value: 49, currency: 'USD' }); fbq('track', 'Purchase', { value: 49, currency: 'USD' }, { eventID: sessionId }); ``` Then: - Sporetag sees the same id from both and counts the order once on the customer. - A sale already sent from the browser or the Events API is not sent again by the connector, and the other way round. - Meta also drops the second copy it gets from the pixel. An `order_id` that matches one of the Stripe ids is treated the same way. ## The attribution report Synced sales appear in the [attribution report](https://sporetag.com/docs/attribution-report) on their real date, under **All goals** and under a goal on `Purchase`. A sale that your site also sent as an event, with the same `event_id` or `order_id`, is counted once. Synced sales do not change your visitor stats and do not count toward your plan's events. ## Sync log The connector's page lists the last 50 runs and webhooks: what was added and any errors. Keys and personal data are never shown there. Rows older than 30 days are deleted. ## If something goes wrong Integrations shows **Needs attention** with the reason: - **Stripe did not accept the key.** It was deleted or expired. Make a new restricted key and paste it under **Paste a new key**. - **The key cannot read Invoices** (or another resource). Edit the key in Stripe and set it to Read. - **Stripe is busy right now.** Nothing to do. Sporetag tries again in 15 minutes. - **Paused. Connectors are on paid plans.** The plan changed to Free. Sync starts again after an upgrade. ## Disconnect Click **Disconnect** on the connector's page. The key and the signing secret are deleted at once, and the tag stops adding ids to Stripe links within a few minutes. Orders already imported stay on your customers. To remove one person's data, use **Delete this customer** on their profile. Delete the restricted key and the webhook in Stripe too. If you connect again later, the endpoint URL stays the same. --- # Shopify connector > Connect a Shopify store with a custom app. Orders, refunds and customers join each customer profile, the attribution report and Meta. Source: https://sporetag.com/docs/shopify-connector Section: Measure The Shopify connector reads your store's orders, refunds and customers and adds them to each [customer profile](https://sporetag.com/docs/customer-profiles). Sales also show in the [attribution report](https://sporetag.com/docs/attribution-report), and live sales can go to Meta. It is on paid plans: Solo, Studio, Agency and Custom. Free does not include it. **Connect with Shopify (when shipped).** A one-click login: type your shop address, click **Connect with Shopify**, approve Sporetag in the new tab, and you are done, with no app to make. Until it is switched on, use the steps below. Sporetag only reads. The app you make has read access only, so it cannot change your store. ## Make a custom app Shopify connects through a custom app that you make for your own store. These steps follow Shopify's help pages as of October 2026. Shopify changes its screens often, so a button may have a slightly different name. 1. In your Shopify admin, go to **Settings**, then **Apps**. Click **Develop apps**, then **Build apps in Dev Dashboard**. 2. In the Dev Dashboard, click **Create app** and name it `Sporetag`. 3. Make a version of the app. Keep the app address Shopify suggests. Under access scopes, add: - `read_orders` - `read_customers` - `read_all_orders`, to import the full 90 days. Without it, Shopify shows apps only the last 60 days of orders. 4. Release the version. 5. Install the app on your store. 6. In the app's settings, find the **Client ID** and **Client secret**. You need to be the store owner, or have the **App development** permission. Shopify's guide: [custom apps](https://help.shopify.com/en/manual/apps/app-types/custom-apps). This works when the app and the store belong to the same Shopify organization, which is the case when you make the app from your own store's admin. An agency connecting a client's store should make the app from that store. ## Connect 1. In Sporetag, open your site, then **Settings**, then **Integrations**. Next to **Shopify**, click **Connect**. 2. Type your shop address, such as `my-shop.myshopify.com`. Find it under **Settings**, then **Domains**. 3. Paste the **Client ID** and **Client secret**, and click **Connect Shopify**. Sporetag gets an access token from Shopify with the client ID and secret. It checks the app has `read_orders` and `read_customers`, and says which one is missing if not. Shopify's tokens last 24 hours, so Sporetag gets a new one when it runs out. The client secret is stored encrypted. It is never shown again, and it never appears in logs. ### An app made in the Shopify admin before 2026 Older custom apps show an **Admin API access token** (it starts with `shpat_`) and an **API secret key**. Leave Client ID empty, paste the API secret key in **Client secret**, and paste the token under **Made your app in the Shopify admin before 2026?** ## What happens next - **The first import** reads orders from the last 90 days. A busy store can take a few hours, since each run reads a small batch. Integrations shows **Importing** and a count. - **Webhooks.** Sporetag adds five webhooks to the app for you: `orders/paid`, `orders/updated`, `refunds/create`, `customers/create` and `app/uninstalled`. They go to `https://sporetag.com/hooks/shopify/...`. New orders then show up in seconds. The connector's page says whether they were added. - **Every 15 minutes**, Sporetag also reads orders that changed since its last check, in case a webhook was missed. - **Sync now** starts a check at once. Each webhook is checked with the `X-Shopify-Hmac-Sha256` header and your client secret, and must come from your shop. Anything else is refused. Sporetag then reads the order again from Shopify, so it never trusts the webhook body alone. ## What shows up on a customer | Shopify | On the customer | |---|---| | A paid order (or partly paid, or refunded later) | **Order**, with the total and product names | | A refund | **Refund**, which lowers revenue | | A new customer | A profile, with no order yet | Orders that are not paid yet, such as cash on delivery, show up once they are paid. Orders and revenue add up into the customer's lifetime value. Revenue adds up in the customer's first currency. ## Who the customer is Sporetag finds the customer by: - the Shopify customer id, - the email and phone on the order (hashed with SHA-256, the way Meta asks), - the visitor's first-party id in the cart attribute `_st_id`. ## Where the sale came from Shopify keeps the first and last visit before an order, with their landing pages and UTM tags. Sporetag reads them, along with click ids such as `fbclid` and `gclid` on the landing page. They move the customer's first and last touch, and the order shows its `utm_source` and `utm_campaign`. For a full journey across visits, pass the first-party id to the order. Your site needs [90-day tracking](https://sporetag.com/docs/tracking-modes) and the 90-day tag on your theme. Then add this before `` in your theme's `theme.liquid` (**Online Store**, **Themes**, **Edit code**): ```html ``` It saves the id on the cart, and Shopify copies cart attributes to the order. The underscore keeps it out of sight at checkout. With **Wait for consent** on, the cookie only exists after the visitor agreed, so nothing is passed before that. UTM tags saved as cart attributes named `utm_source`, `utm_campaign`, `utm_content` and `utm_term` are read too, when Shopify has no journey for the order. ## Goals and Meta Synced orders count as the **Purchase** event. They reach any goal on the event `Purchase`. When that goal is set to send to Meta (see [Meta Conversions API](https://sporetag.com/docs/meta-conversions-api)), a new order goes to Meta once: - Only live orders: ones placed in the last 24 hours. The 90-day import never sends old orders. - The hashed email and phone go along, and the buyer's IP address and browser when Shopify kept them. Meta has no documented way to change a sale once it is sent, so a refund is not sent to Meta. Google Ads and Microsoft Ads do take refunds: see [Refunds](https://sporetag.com/docs/send-results-to-ad-accounts#refunds). ### The event_id rule The connector uses `shopify-` and the order id as the `event_id`, such as `shopify-5523018432`. That is the same id the [Events API Shopify example](https://sporetag.com/docs/events-api#from-a-shopify-webhook) uses. If you also send orders from the browser or the Events API, use that `event_id`, or send the order number as `order_id`. Then: - Sporetag counts the order once on the customer. - An order already sent to Meta from the browser or the Events API is not sent again by the connector, and the other way round. The order id, the order name (`#1042`) and the order number (`1042`) all match the same order. ## The attribution report Synced orders appear in the [attribution report](https://sporetag.com/docs/attribution-report) on their real date, under **All goals** and under a goal on `Purchase`. An order that your site also sent as an event, with the same `event_id` or `order_id`, is counted once. Synced orders do not change your visitor stats and do not count toward your plan's events. ## If something goes wrong Integrations shows **Needs attention** with the reason: - **Shopify did not accept the client ID and secret.** Check them, and that the app is installed on this store. Paste them again under **Paste new app details**. - **The app is missing read_orders.** Add the scope in a new version of the app, release it, then paste the details again. - **Shopify is busy right now.** Nothing to do. Sporetag tries again in 15 minutes. - **Paused. Connectors are on paid plans.** The plan changed to Free. Sync starts again after an upgrade. The connector's page lists the last 50 runs and webhooks. Keys and personal data are never shown there. ## Disconnect Click **Disconnect** on the connector's page. Sporetag removes the webhooks it added, then deletes the client secret and token at once. Orders already imported stay on your customers. To remove one person's data, use **Delete this customer** on their profile. You can also uninstall the app in Shopify. If you uninstall a custom app you made, the connector shows **Needs attention**. Your data stays. Make the app again and paste its details. ## Privacy requests from Shopify These apply when you connect with **Connect with Shopify (when shipped)**, which uses Sporetag's own Shopify app. - **A customer asks for their data.** Shopify tells Sporetag. Sporetag emails you what it holds about that customer for each site linked to the store: contact details it keeps, what they are known by, totals, and their orders and visits. Send it to the customer with what your store holds. - **A customer asks to be deleted.** Sporetag deletes their profile, its ids and the orders Shopify names, on each linked site. Their ids are never linked again on that site. - **You uninstall the app.** Syncing stops at once and the login is deleted. 48 hours later, Sporetag deletes the store's orders, the profiles that only came from Shopify, and the connection. Profiles your site knows in other ways stay, with the Shopify sales taken off. Install the app again within 48 hours to keep the data. The connector's log lists each request. It never shows the customer's details. --- # Klaviyo connector > Connect Klaviyo with a private API key. Email and text activity joins each customer, and sources, value, best send hour and segments go back. Source: https://sporetag.com/docs/klaviyo-connector Section: Measure The Klaviyo connector works in two directions: - **In:** email and text sends, opens, clicks and unsubscribes join each [customer profile](https://sporetag.com/docs/customer-profiles). - **Out:** Sporetag writes each customer's first and last source, lifetime value, orders and best send hour onto their Klaviyo profile. Segments you pick become Klaviyo lists. It is on paid plans: Solo, Studio, Agency and Custom. Free does not include it. **Connect with Klaviyo (when shipped).** A one-click login: click **Connect**, log in to Klaviyo in the new tab and allow access, and you are done, with no key to paste. Until it is switched on, use the steps below. ## Connect 1. In Sporetag, open your site, then **Settings**, then **Integrations**. Under **Email and texts**, click **Connect** next to **Klaviyo**. 2. In Klaviyo, click your account name, then **Settings**, then **API keys**. Click **Create Private API Key**. 3. Name it `Sporetag` and pick **Custom Key**. Set these, and leave everything else at **No Access**: | Scope | Access | Why | |---|---|---| | Events | Read | Sends, opens, clicks and unsubscribes | | Metrics | Read | To find those events in your account | | Profiles | Full | To read who each event is about, and to write the Sporetag properties | | Lists | Full | To keep segment lists up to date | 4. Click **Create**. Copy the key. It starts with `pk_`. 5. Paste it into Sporetag and click **Connect Klaviyo**. Sporetag checks that the key can read Events, Metrics and Profiles. Klaviyo has no way to check a write scope without writing, so a missing Profiles or Lists write scope shows up on the first send back, with the scope to fix. Klaviyo does not let you change a key's scopes later. To fix one, make a new key and paste it under **Paste a new key**. The key is stored encrypted. It is never shown again, and it never appears in logs. ## What comes in Sporetag reads these Klaviyo events: | Klaviyo event | On the customer | |---|---| | Received Email | **Email sent** | | Opened Email | **Email opened** | | Clicked Email | **Email clicked**, with the link (without its query string) | | Unsubscribed from Email Marketing | **Unsubscribed from email** | | Received SMS | **Text sent** | | Clicked SMS | **Text clicked** | Each item shows the email subject or campaign name. - **The first import** reads the last 90 days. A busy account can take a few hours, since each run reads a batch. - **After that**, Sporetag checks every 15 minutes, and reads one day back each time, so late events are not missed. Each event is stored once. ### Who the customer is Sporetag finds the customer by the Klaviyo profile id, and by the profile's email and phone (hashed with SHA-256, as everywhere in Sporetag). - A **click** or an **unsubscribe** can add a new customer. - A **send** or an **open** only joins a customer Sporetag already knows. Sends are many, and most mail apps open some mail on their own, so on their own they say little. If the profile has a time zone, Sporetag keeps it for the [best send time](https://sporetag.com/docs/segments-and-best-send-time). ## What goes back For people Klaviyo already has, Sporetag keeps these profile properties up to date: | Property | What it holds | |---|---| | `sporetag_first_source` | Where they first came from, like `instagram` | | `sporetag_last_source` | Where they came from last | | `sporetag_ltv` | Lifetime value | | `sporetag_orders` | Number of orders | | `sporetag_best_send_hour` | Their best hour to get a message, 0 to 23, in their time zone | | `sporetag_timezone` | The time zone that hour is in | Use them in Klaviyo segments and flows. For example, a flow can wait until `sporetag_best_send_hour`, or a segment can pick people whose `sporetag_first_source` is `tiktok`. - Sporetag only updates people who came from Klaviyo. It never adds new profiles and never changes consent. - A profile is sent again only when one of its values changed. - To stop, click **Stop sending back** on the connector's page. ### Segments as lists Each [segment](https://sporetag.com/docs/segments-and-best-send-time) you send to Klaviyo becomes a static list named `Sporetag: ` and the segment's name. Sporetag adds people who match and removes people who stop matching, every 15 minutes. Klaviyo's own segments are built from rules inside Klaviyo, so another tool cannot add people to them. That is why Sporetag uses a list. Build a Klaviyo segment on top of the list if you like. Renaming a segment in Sporetag does not rename the list. If you delete the list in Klaviyo, Sporetag makes it again. ## Sync log The connector's page lists the last 50 runs: what was added, profiles updated and segment changes, and any errors. Keys and personal data are never shown there. ## If something goes wrong - **Klaviyo did not accept the key.** It was deleted. Make a new private key and paste it. - **The key cannot read Events** (or another scope). Make a new key with that scope set as in the table above. - **Klaviyo is busy right now.** Nothing to do. Sporetag tries again in 15 minutes. - **Paused. Connectors are on paid plans.** The plan changed to Free. ## Disconnect Click **Disconnect** on the connector's page. The key is deleted at once. Items already imported stay on your customers, and the properties and lists stay in Klaviyo. Delete the key in Klaviyo too. --- # Mailchimp connector > Connect Mailchimp with an API key. Campaign sends, opens, clicks and unsubscribes join each customer, and Sporetag writes back merge fields and tags. Source: https://sporetag.com/docs/mailchimp-connector Section: Measure The Mailchimp connector works in two directions: - **In:** campaign sends, opens, clicks and unsubscribes join each [customer profile](https://sporetag.com/docs/customer-profiles). - **Out:** Sporetag writes each customer's first and last source, lifetime value, orders and best send hour into merge fields. Segments you pick become tags. It is on paid plans: Solo, Studio, Agency and Custom. Free does not include it. **Connect with Mailchimp (when shipped).** A one-click login: click **Connect**, log in to Mailchimp in the new tab and allow access, and you are done, with no key to paste. Until it is switched on, use the steps below. ## Connect 1. In Sporetag, open your site, then **Settings**, then **Integrations**. Under **Email and texts**, click **Connect** next to **Mailchimp**. 2. In Mailchimp, click your profile icon, then **Profile**. Open **Extras**, then **API keys**. 3. Click **Create A Key** and name it `Sporetag`. 4. Copy the whole key. It ends with a dash and your server, like `-us6`. 5. Paste it into Sporetag and click **Connect Mailchimp**. Sporetag reads your server from the end of the key, so you never type it. Mailchimp keys cannot be limited to some data. Any key can read and change the whole account. Sporetag only reads campaign reports and writes its own merge fields and tags. If that is too much access for you, use the [Events API](https://sporetag.com/docs/bring-your-data-together) from a tool such as Zapier instead. The key is stored encrypted. It is never shown again, and it never appears in logs. ## What comes in Sporetag reads Mailchimp's campaign reports: | Mailchimp report | On the customer | |---|---| | Sent to | **Email sent** | | Email activity: open | **Email opened** | | Email activity: click | **Email clicked**, with the link (without its query string) | | Unsubscribes | **Unsubscribed from email** | Each item shows the campaign's subject line. - **The first import** reads campaigns sent in the last 90 days, up to 100 campaigns. - **After that**, every 15 minutes, Sporetag reads opens, clicks and unsubscribes for campaigns sent in the last 30 days, and sends for new campaigns. - Automated emails (Customer Journeys) have no campaign report in Mailchimp's API, so they are not read. Their clicks still show up as visits when the links carry UTM tags. ### Who the customer is Sporetag finds the customer by the member's email (hashed with SHA-256) and by Mailchimp's member id in each audience. - A **click** or an **unsubscribe** can add a new customer. - A **send** or an **open** only joins a customer Sporetag already knows. ## What goes back Mailchimp merge tags are at most 10 characters, so the names are short. Sporetag makes these fields in each audience the first time, hidden from signup forms: | Merge tag | Field name | What it holds | |---|---|---| | `STFIRST` | Sporetag first source | Where they first came from | | `STLAST` | Sporetag last source | Where they came from last | | `STLTV` | Sporetag lifetime value | Lifetime value | | `STORDERS` | Sporetag orders | Number of orders | | `STBESTHR` | Sporetag best send hour | Their best hour, 0 to 23, in their time zone | | `STTZ` | Sporetag time zone | The time zone that hour is in | - Sporetag only updates members Mailchimp already has. It never adds members and never changes their status. - A member is sent again only when one of the values changed. - Your plan limits how many merge fields an audience can have. If an audience is full, those fields are not made. - To stop, click **Stop sending back** on the connector's page. ### Segments as tags Each [segment](https://sporetag.com/docs/segments-and-best-send-time) you send to Mailchimp becomes a tag named `Sporetag: ` and the segment's name. Sporetag adds the tag to members who match and takes it off members who stop matching, every 15 minutes. ## If something goes wrong - **Mailchimp did not accept the key.** It was turned off or deleted. Make a new key and paste it. - **Mailchimp is busy right now.** Nothing to do. Sporetag tries again in 15 minutes. - **Paused. Connectors are on paid plans.** The plan changed to Free. ## Disconnect Click **Disconnect** on the connector's page. The key is deleted at once. Items already imported stay on your customers, and the fields and tags stay in Mailchimp. Delete the key in Mailchimp too. --- # Attentive connector > Connect Attentive with a custom app. Text and email sends and clicks arrive by webhook, and Sporetag sends back custom attributes and segments. Source: https://sporetag.com/docs/attentive-connector Section: Measure The Attentive connector works in two directions: - **In:** Attentive tells Sporetag about texts and emails as they go out, get opened and get clicked. They join each [customer profile](https://sporetag.com/docs/customer-profiles). - **Out:** Sporetag writes each customer's first and last source, lifetime value, orders and best send hour as custom attributes. Segments you pick become Attentive segments. It is on paid plans: Solo, Studio, Agency and Custom. Free does not include it. ## What Attentive allows Checked against Attentive's developer docs in October 2026: - Attentive's public API has **no way to read past messages or clicks**. It sends them as they happen, through a webhook. So Sporetag sees messages from the day you turn the webhook on. Nothing older is imported. - Custom attributes and segments are written **by email or phone**. Sporetag updates people by email. That needs **Show contact details** on for the site. People Sporetag knows only by phone are skipped. - Attentive's Segments API is an **open beta**. Attentive may change it. ## Connect 1. In Sporetag, open your site, then **Settings**, then **Integrations**. Under **Email and texts**, click **Connect** next to **Attentive**. 2. In Attentive, open **Integrations**, then **Custom apps**, and click **Create app**. Name it `Sporetag`. 3. Under permissions, set **Custom Attributes** and **Segments** to write. Leave the rest off. 4. Click **Create**. Copy the API key. 5. Paste it into Sporetag and click **Connect Attentive**. Sporetag checks the key with Attentive. It is stored encrypted, never shown again, and never appears in logs. ## Turn on the webhook 1. Open the Attentive connector's page in Sporetag and copy the **Webhook address**. It looks like `https://sporetag.com/hooks/attentive/...`. 2. In Attentive, open the Sporetag app, then the **Webhooks** tab. Turn on **Event Webhook Status**. 3. Pick **Universal webhook** and paste the address as the **HTTP Post URL**. 4. Pick these events: - `sms.sent` - `sms.message_link_click` - `sms.unsubscribed` - `email.sent` - `email.opened` - `email.message_link_click` - `email.unsubscribed` 5. Copy the **Signing key** and paste it into Sporetag under **Messages from Attentive**. Save in Attentive. Sporetag checks the signature (`x-attentive-hmac-sha256`) on every webhook and refuses any that do not match. Attentive asks that each event type goes to one app only. If another app already listens to an event, pick the rest. ## What comes in | Attentive event | On the customer | |---|---| | `sms.sent` | **Text sent** | | `sms.message_link_click` | **Text clicked**, with the link (without its query string) | | `sms.unsubscribed` | **Unsubscribed from texts** | | `email.sent` | **Email sent** | | `email.opened` | **Email opened** | | `email.message_link_click` | **Email clicked** | | `email.unsubscribed` | **Unsubscribed from email** | Sporetag finds the customer by Attentive's subscriber id and by the email and phone (hashed with SHA-256). The phone number itself is never stored. - A **click** or an **unsubscribe** can add a new customer. - A **send** or an **open** only joins a customer Sporetag already knows. A webhook sent twice is stored once. ## What goes back For people Attentive already sent to, and whose email Sporetag keeps, these custom attributes stay up to date: | Attribute | What it holds | |---|---| | `sporetag_first_source` | Where they first came from | | `sporetag_last_source` | Where they came from last | | `sporetag_ltv` | Lifetime value | | `sporetag_orders` | Number of orders | | `sporetag_best_send_hour` | Their best hour, 0 to 23, in their time zone | | `sporetag_timezone` | The time zone that hour is in | Attentive types an attribute from the first value it gets. Sporetag sends every value as text, so the types stay the same. Each [segment](https://sporetag.com/docs/segments-and-best-send-time) you send to Attentive becomes a segment named `Sporetag: ` and the segment's name. Sporetag adds and removes members every 15 minutes. To stop, click **Stop sending back** on the connector's page. ## Disconnect Click **Disconnect** on the connector's page. The key and the signing key are deleted at once, and the webhook address stops answering. Items already imported stay on your customers. Turn off the webhook and remove the app in Attentive too. --- # HubSpot and GoHighLevel > Connect HubSpot or GoHighLevel with one login (when shipped). Won deals count as sales, and each profile goes back with where the person came from. Source: https://sporetag.com/docs/crm-connectors Section: Measure The HubSpot and GoHighLevel connectors work in two directions: - **In:** contacts join your [customer profiles](https://sporetag.com/docs/customer-profiles). Deal stages, wins and losses show on each person's timeline. A won deal counts as a sale in revenue and in the [Attribution report](https://sporetag.com/docs/attribution-report). - **Out:** Sporetag sends each person who gave you an email to your CRM as a contact, with their first and last source, campaign, ad platform, landing page, short link, visits, revenue and orders. It is on paid plans: Solo, Studio, Agency and Custom. Free does not include it. Each connector needs Sporetag's own HubSpot or GoHighLevel app. Until it is set up for this server, the row says **(when shipped)**. A [webhook](https://sporetag.com/docs/webhooks-out) to Zapier or Make can do the same job until then. ## Connect 1. In Sporetag, open your site, then **Settings**, then **Integrations**. Under **CRMs and sending**, click **Connect** next to **HubSpot** or **GoHighLevel**. The login opens in a new tab. 2. Log in and approve what Sporetag asks for. - **HubSpot:** pick the HubSpot account if you have more than one. - **GoHighLevel:** pick one sub-account (location). Agency logins are not supported. Connect each client's sub-account on that client's site. 3. You land on the connector's page. The import of the last 90 days starts right away. What Sporetag asks for: | Tool | Permissions | Why | |---|---|---| | HubSpot | `crm.objects.contacts.read`, `crm.objects.deals.read` | Read contacts and deals | | HubSpot | `crm.objects.contacts.write`, `crm.schemas.contacts.read`, `crm.schemas.contacts.write` | Send profiles back, and add the Sporetag properties | | GoHighLevel | `contacts.readonly`, `opportunities.readonly`, `locations.readonly` | Read contacts, opportunities and the sub-account name | | GoHighLevel | `contacts.write`, `locations/customFields.readonly`, `locations/customFields.write` | Send profiles back, and add the Sporetag custom fields | Sporetag never deletes anything in your CRM, and never changes a deal or an opportunity. If you already connected the same CRM account on another site, the page offers **Use** that login, so you do not log in again. ## What comes in - **Contacts** made in the last 90 days become customer profiles, with an **Added to CRM** item. The item keeps the CRM's own source, like "Paid social, Facebook" in HubSpot or "Facebook form" in GoHighLevel. - **Older contacts** only join people Sporetag already knows (by email or phone). A big CRM does not fill your profiles with people who never visited. - **UTM tags and click ids** the CRM kept become the person's first touch, when they are older than what Sporetag saw. HubSpot keeps them in the first page address. GoHighLevel keeps them in the contact's attribution. - **Deals** (HubSpot) and **opportunities** (GoHighLevel): each stage the deal entered is a **Deal stage changed** item, then **Deal won** or **Deal lost**. HubSpot keeps every stage with its time. GoHighLevel only says the current stage, so Sporetag stores the stages it sees. After the first import, Sporetag checks every 15 minutes, and reads one day back each time so late changes are not missed. Each item is stored once. ### Won deals as sales A won deal with a value counts as a sale: - It adds to the person's orders and revenue. - It counts as a conversion of your goals on the `Purchase` event in the Attribution report, at the time it was won. When the person never visited your site, the deal is credited to the UTM tags on their CRM contact. - It counts once, however often Sporetag reads it. Its id is `hubspot-deal-` or `ghl-opp-` and the CRM's id. - It is never sent to Meta, since it is not a website purchase. A deal won in the last 3 days also starts any [automation](https://sporetag.com/docs/automations) that begins with **A deal is won in your CRM**. A flow can send someone to your CRM too, with a **Push to CRM** step. If the same sales already come from [Stripe](https://sporetag.com/docs/stripe-connector) or [Shopify](https://sporetag.com/docs/shopify-connector), turn off **Count won deals as sales**. The wins stay on the timeline, with their amount, but are not counted twice. The switch applies to deals won from then on. **GoHighLevel:** its API does not say which currency your opportunity values are in. Pick it under **Contacts and opportunities in**. It is USD until you do. ## What goes out Under **Send profiles to HubSpot** (or GoHighLevel), tick the fields to send and click **Start sending**. | Field | HubSpot property | GoHighLevel custom field | |---|---|---| | Name | First name and last name | First name and last name | | Phone | Phone number | Phone | | First source, campaign and ad platform | `sporetag_first_source`, `sporetag_first_campaign`, `sporetag_first_platform` | Sporetag first source, and so on | | First seen | `sporetag_first_seen` (a date) | Sporetag first seen | | Last source, campaign and ad platform | `sporetag_last_source`, `sporetag_last_campaign`, `sporetag_last_platform` | Sporetag last source, and so on | | Landing page | `sporetag_landing_page` | Sporetag landing page | | Short link | `sporetag_short_link` | Sporetag short link | | Visits, revenue, orders | `sporetag_visits`, `sporetag_revenue`, `sporetag_orders` | Sporetag visits, and so on | | Profile | `sporetag_profile_url` (a link to the profile in Sporetag) | Sporetag profile | - Sporetag makes the properties (in a HubSpot group named **Sporetag**) and the custom fields the first time it sends. - People are matched on email. Someone new is added as a contact. Someone the CRM has is updated. - Name and phone replace what the CRM has. Untick them to leave the CRM's own. - A field with no value is left out, never sent empty. - Pick a [segment](https://sporetag.com/docs/segments-and-best-send-time) under **Who** to send only some people. ### When people go out - **Right away** when your site identifies someone with an email: a form, a checkout on your site, or `sporetag('identify')`. - **Within 15 minutes** for everyone else whose profile changed: a Stripe or Shopify sale, an import, a new touch. - **Send everyone now** sends every profile once more. A profile goes out again only when one of its values changed. ### Who is not sent - People with no email. - Everyone, while **Show contact details** is off. Sporetag then keeps only hashed emails, so it has no email to send. Turn it on in the Customers tab. - People Sporetag only knows from this same CRM. There is nothing new to add. ## When something fails A failed send waits 1, 5, 15, 30, then 60 minutes before the next try, without a warning. From the sixth failure in a row, the row says **Needs attention** with the reason, and Sporetag keeps trying every 15 minutes. If the login ends, the row says **Reconnect**. One click opens the login again. Nothing already imported is lost. ## Disconnect **Disconnect** on the connector's page deletes the saved login and stops sending. Contacts and deals already imported stay on your customers. Properties and contacts already in your CRM stay there. --- # Airtable > Send each customer profile, with where they came from and what they spent, to an Airtable table (when shipped). Orders can get their own table. Source: https://sporetag.com/docs/airtable-connector Section: Measure The Airtable connector keeps a table of your customers up to date: one row per person who gave you an email, with their first and last source, campaign, ad platform, landing page, short link, visits, revenue and orders. It can also add one row per order to a second table. It is on paid plans: Solo, Studio, Agency and Custom. Free does not include it. It needs Sporetag's own Airtable integration. Until it is set up for this server, the row says **(when shipped)**. A [webhook](https://sporetag.com/docs/webhooks-out) to Zapier or Make can fill a table until then. ## Connect 1. In Sporetag, open your site, then **Settings**, then **Integrations**. Under **CRMs and sending**, click **Connect** next to **Airtable**. The login opens in a new tab. 2. Log in to Airtable. Pick the bases Sporetag may use, and click **Grant access**. 3. Back in Sporetag, pick the **Base**, then the **Table**. Pick **Make a "Sporetag profiles" table for me** to start fresh. 4. Tick the fields to send, and click **Start sending**. What Sporetag asks for: | Permission | Why | |---|---| | `data.records:read`, `data.records:write` | Add and update rows | | `schema.bases:read` | List your bases, tables and columns | | `schema.bases:write` | Make the table and add missing columns | To make a table or add columns you need to be a creator on the base. ## Columns Each field goes in a column named like the field, such as **Sporetag first source**. Change a name under **Column names** to use a column you already have. - Rows are matched on the **Email** column, so each person is one row. Change its name if your table uses another. - Missing columns are added with the right type: text, number, date or link. Sporetag never renames or deletes a column. - A field with no value is left out, so Sporetag never empties a cell. ## Orders Tick **Also add one row per order**. Sporetag makes a **Sporetag orders** table with Order ID, Email, Date, Value, Currency, Source, Kind and Title. Orders from Stripe, Shopify, the Events API and won CRM deals go in, one row each, matched on Order ID. ## When rows go out - **Right away** when your site identifies someone with an email. - **Within 15 minutes** for everyone else whose profile changed. - **Send everyone now** sends every profile once more. Airtable takes up to 10 rows a request and 5 requests a second to a base. Sporetag keeps to that, so a big first send takes a few minutes. If Airtable asks it to slow down, it waits 30 seconds and carries on. People with no email are not sent. While **Show contact details** is off, nobody is sent, since Sporetag keeps only hashed emails. ## When something fails A failed send waits 1, 5, 15, 30, then 60 minutes before the next try. From the sixth failure in a row, the row says **Needs attention** with the reason. A deleted table or base says so: pick a table again. An Airtable login ends after 60 days without use. While sending is on, Sporetag renews it on its runs, so it stays alive. If it ends, the row says **Reconnect**. ## Disconnect **Disconnect** deletes the saved login and stops sending. Rows already in Airtable stay there. --- # Webhooks out > Post each customer profile, and optionally each order, to Zapier, Make, n8n or your own server. Signed, retried, and testable. Source: https://sporetag.com/docs/webhooks-out Section: Measure A webhook sends each customer profile to an address you choose, as JSON. Use it to reach any tool through Zapier, Make or n8n, or your own server. It carries the same fields as the [HubSpot and GoHighLevel](https://sporetag.com/docs/crm-connectors) push. It is on paid plans: Solo, Studio, Agency and Custom. Free does not include it. ## Set up 1. In Zapier, Make or n8n, start a flow with a **Webhook** trigger that catches a POST. Copy its address. 2. In Sporetag, open your site, then **Settings**, then **Integrations**. Under **CRMs and sending**, click **Set up** next to **Webhook**. 3. Paste the address and click **Save**. It must start with `https://` and be on a public host name. 4. Click **Send test**. Sporetag posts a sample event, marked `"test": true`, and shows the answer. 5. Build the rest of your flow from the test event. 6. Tick the fields to send and click **Start sending**. Tick **Also send one event per order** to get orders, renewals and won deals too. ## Events Each request is one event. Every event has the same outer shape: ```json { "id": "evt_3f9c2a7b1d0e4c55a8e2f901", "type": "profile.updated", "created": "2026-10-23T14:02:11.000Z", "site": { "id": "a4bd9d08183f00a2", "domain": "plantshop.com" }, "data": { "profile_id": "Xk29dLq0aB7cZp", "email": "sam@example.com", "name": "Sam Rivera", "currency": "USD", "sporetag_first_source": "instagram", "sporetag_first_campaign": "spring-sale", "sporetag_first_platform": "Meta", "sporetag_first_seen": "2026-10-01", "sporetag_last_source": "google", "sporetag_landing_page": "/shop", "sporetag_short_link": "go.sporetag.com/spring", "sporetag_visits": 4, "sporetag_revenue": 120, "sporetag_orders": 2, "sporetag_profile_url": "https://sporetag.com/app/s/a4bd9d08183f00a2/customers/Xk29dLq0aB7cZp" } } ``` This is demo data. Only the fields you ticked are in `data`, and a field with no value is left out. | Type | When | `data` | |---|---|---| | `profile.updated` | A person with an email is new or changed | The profile, as above | | `order.created` | An order, renewal or won deal, if you turned orders on | `order_id`, `profile_id`, `email`, `occurred_at`, `value`, `currency`, `source`, `kind`, `title` | | `test` | You clicked **Send test** | A sample profile | The `Sporetag-Event` header holds the type too. ## Check the signature Each request has a `Sporetag-Signature` header: ``` Sporetag-Signature: t=1792764131,v1=5f2b...e9 ``` `t` is the time in Unix seconds. `v1` is a hex HMAC-SHA256 of `t`, a dot, and the raw body, made with your signing secret. Find the secret under **Signing secret** on the webhook page. To check a request: 1. Read `t` and `v1` from the header. 2. Compute HMAC-SHA256 of `t + "." + body` with the secret, as hex. 3. Compare it with `v1`. Reject the request if they differ, or if `t` is more than 5 minutes old. **Make a new secret** replaces it at once. Update it where you check signatures. ## Retries An answer other than 2xx within 10 seconds is a failure. Sporetag tries again after 1, 5, 15, 30, then 60 minutes. From the sixth failure in a row, the row says **Needs attention**, and Sporetag keeps trying every 15 minutes. A retry can send an event you already got. Use `id` to skip one you have seen: the same profile with the same values has the same `id`. ## When events go out - **Right away** when your site identifies someone with an email. - **Within 15 minutes** for everyone else whose profile changed. - **Send everyone now** sends every profile once more. People with no email are not sent. While **Show contact details** is off, nobody is sent, since Sporetag keeps only hashed emails. ## Stop **Stop sending** pauses it. **Disconnect** deletes the address and the secret. --- # Postscript connector > Postscript limits its API to integration partners and enterprise shops, so there is no Postscript connector yet. What works today with UTM tags and webhooks. Source: https://sporetag.com/docs/postscript-connector Section: Measure There is no Postscript connector yet (when shipped). ## Why Postscript calls its API a Partner API. Its own docs (checked October 2026) say: - Since April 2022, a shop can use its own API key for its own code only on an enterprise plan. - Other shops can make keys, but only for Postscript's integration partners. - The webhooks Postscript sends are for opt ins, opt outs, replies and collected emails. There is no webhook for a text sent or a link clicked. Sporetag is not a Postscript integration partner today. Building a connector on a shop's key would break those terms for most shops, so Sporetag does not. ## What works today **Clicks from texts.** Add UTM tags to the links in your Postscript messages, with `utm_medium=sms`: ``` https://yourshop.com/products/mug?utm_source=postscript&utm_medium=sms&utm_campaign=fall-sale ``` With the Sporetag script on your site, each visit from a text shows as **Text clicked** on the customer, with the campaign. With 90-day tracking, it ties to the person once they are identified. See [UTM presets](https://sporetag.com/docs/utm-presets). **Opt ins and opt outs.** If your shop has API access, point a Postscript webhook at a small script or a Zapier step that sends them to the [Events API](https://sporetag.com/docs/bring-your-data-together) with `kind` set to `sms_unsubscribed` and `source` set to `postscript`. **Sending data to Postscript.** Not possible from Sporetag today. Export a segment from the Profiles tab as CSV if you need the list. --- # Segments and best send time > Group customers by source, spend and activity, send groups to Klaviyo, Mailchimp or Attentive, and reach each person at the hour they are most likely to act. Source: https://sporetag.com/docs/segments-and-best-send-time Section: Measure Two things Sporetag knows that your email and text tools do not: where each customer came from, and when they tend to act. Segments and the best send time put that to work. Both are on paid plans: Solo, Studio, Agency and Custom, with [customer profiles](https://sporetag.com/docs/customer-profiles) filling in. ## Segments A segment is a saved group of customers. Open your site's **Profiles** tab, then **Segments**, then **New segment**. Pick any of these. A customer has to match all of the ones you pick: | Rule | Matches | |---|---| | First source | Where they first came from, like `instagram` | | Last source | Where they came from most recently | | Ad platform, campaign, short link | On the first or the last touch (under **More options**) | | Orders, at least | People with this many orders or more | | Lifetime value from, to | People who spent in this range | | Last seen | Seen in the last 7, 30, 90, 180 or 365 days | | Email and texts | Opened or clicked an email, clicked a text, or either, in the last 90 days | **Count people** shows how many match before you save. After saving, **See them** opens the customer list filtered to the segment, and **Export CSV** there downloads it. A site can have up to 50 segments. ### Send a segment to your email or text tool Under **Send to**, tick any connected [Klaviyo](https://sporetag.com/docs/klaviyo-connector), [Mailchimp](https://sporetag.com/docs/mailchimp-connector) or [Attentive](https://sporetag.com/docs/attentive-connector). Then: | Tool | The segment becomes | |---|---| | Klaviyo | A list named `Sporetag: ` and the segment name | | Mailchimp | A tag with that name on each member | | Attentive | A segment with that name | Every 15 minutes, Sporetag adds people who now match and removes people who stopped matching. - Only people the tool already has are sent. Sporetag never adds new contacts to a tool and never changes anyone's consent. - Attentive is updated by email, so it needs **Show contact details** on. - Unticking a tool, or deleting the segment, stops the updates. The list, tag or segment stays in the tool. ## Best send time Each customer page has a **Best time to send** card: the hour and day that person is most likely to act, and the time zone it is in. ### How it is worked out Every time a customer does something, Sporetag adds a weight to that hour of their week: | What they did | Weight | |---|---| | An order | 4 | | A click (email, text or short link) | 3 | | A visit or an event | 2 | | An email open | 1 | | An email or text sent to them | 0 | Opens count little because many mail apps open mail on their own. Sends count nothing: they say when you mailed, not when the person was around. Then: 1. The week is moved into the customer's time zone, from their Klaviyo profile when it has one, else your site's time zone. 2. Each hour is smoothed with the hours next to it, so 6:55 and 7:05 count together. 3. The busiest hour of the day is the best send hour. The busiest day is the best day. **Customers with little history** (less than about two clicks' worth) get your site's pattern instead: everyone's weeks added up, each person counted once, so a few busy customers do not decide for all. The card says when it uses the site's pattern. Times move by whole hours at today's offset from UTC. A time zone with a half hour, or a visit from before a daylight saving change, can be an hour off. ### Best hours on the Profiles tab The **Best hours to send** card shows the site's pattern by hour of the day, with the best hour and day. Your site's time zone is the one most of your customers have, or UTC when none is known. To set it, open **Times in ...** under the chart, pick yours and save. ### What your tools get Each connected tool gets `sporetag_best_send_hour` (0 to 23) and `sporetag_timezone` (Mailchimp: `STBESTHR` and `STTZ`) on each person. Build segments in the tool on them, such as people whose best hour is between 6 PM and 9 PM, and send each group at its hour. --- # Automations > Flows that act at the moments that matter: an email when someone signs up, a reminder when a checkout stalls, a note to you when a lead looks at pricing. Source: https://sporetag.com/docs/automations Section: Measure An automation (a flow) waits for a moment, like a signup or a stalled checkout, then runs its steps for that one person. **Automations** in the sidebar holds every flow on every site in one place: the site, the flow's status (Live, Draft or Paused), its trigger, how many people are **in it now**, what it **sent** and its **sales** in the last 30 days, and its **last run**. Filter by status, search by name, or pick a site; the site shows as a chip, and its **x** shows every site again. Each flow belongs to one site. With more than one site, **New flow** and **Use this** on a template ask which site; with one site, they ask nothing. Automations are on paid plans: Solo, Studio and Agency. Free shows the page with the plans. ## Make a flow 1. Open **Automations** in the sidebar. A new account starts on the templates. 2. Press **Use this** on a template, such as **Welcome new signups** or **Abandoned checkout**, or press **New flow** to start blank. 3. Press the trigger at the top to choose what starts the flow. 4. Press **+** between steps to add one. Press a step to change it in the panel on the right (on a phone it slides up from the bottom). 5. Drag a step by its handle to move it, or use the up and down arrows in the panel. 6. Press **Test run**, pick a person, and read what each step would do for them. Nothing is sent. 7. Press **Publish**. The flow is live. Changes save as you go, as a draft. People already in a flow keep the version they started on. **Publish changes** makes a new version for everyone who starts after that. **Pause** stops new people from starting; people on the way wait until you press **Resume**. ## Manage flows Each flow's **⋯** menu has **Edit**, **Rename** (type the new name in place, Enter to keep it), **Open in new tab**, **Publish** (or **Pause** and **Resume** once it is live), **Duplicate** and **Delete**. With more than one site, **Copy to** puts a draft copy on another site. - **Delete** keeps the flow for 30 days under **Deleted**, where **Restore** brings it back, paused, so it never starts sending on its own. After 30 days it is gone for good, with its numbers. Deleting a live flow asks once: the people in it stop there. - **Undo** shows for a few seconds after a delete. - Tick flows to **Pause**, **Delete** or **Move to site** them together. On a computer the tick box shows when you point at a flow. A moved flow arrives paused, and the people in it stop, since people belong to a site. ## Triggers | Trigger | Starts when | |---|---| | Someone gives their email or phone | A profile gets an email or phone for the first time: a website form, the Events API, a connected store or tool. Never from an import. Pick **Website forms only** to start only from forms | | Someone reaches a goal | Any goal, or the one you pick | | First visit from an ad | Their first visit, with an ad click id in the address. Any ad platform, or the one you pick | | Someone comes back after a while | They visit again after at least the days you set | | Someone visits a page | A page like `/pricing`. Use `*` for any part, like `/pricing*` | | Checkout started, no purchase | They reach a checkout page (like `/checkout*`) or send a checkout event (like `InitiateCheckout`), then buy nothing within the minutes you set | | Someone buys | A sale from Stripe, Shopify, the Events API or your script, optionally above an amount. One sale starts a flow once, even when two sources report it | | Someone clicks a short link | They visit through any short link, or the one you pick | | Someone joins a segment | They join a [segment](https://sporetag.com/docs/segments-and-best-send-time). Checked every 15 minutes. People already in it when you publish are left out | | Someone enters a stage | They become a Lead, Engaged, Customer, Repeat, At risk or Unsubscribed (see [stages](https://sporetag.com/docs/messages#stages)). Checked every 15 minutes, like a segment. People already in it when you publish are left out, and someone who leaves the stage and comes back does not start it again | | Only people you add | Nobody starts it on their own. Add people from Profiles: filter by stage, then **Add to automation** | | A deal is won in your CRM | A deal is marked won in [HubSpot or GoHighLevel](https://sporetag.com/docs/crm-connectors), for the person on the deal. Needs one of them connected. Only deals won in the last 3 days start it, so connecting a CRM never starts it for old deals. One deal starts a flow once | Triggers that come from visits (goals, pages, ads, links, checkouts, coming back) need [90-day tracking](https://sporetag.com/docs/tracking-modes), and consent where the site waits for it, because they follow one person. **Can someone go through it again?** **Once only**, **Again after some days**, or **Every time** (one run at a time). **Stop when they buy** ends their run as soon as a sale comes in. Abandoned checkout flows always stop on a purchase. Ask the [assistant](https://sporetag.com/docs/assistant) to "Set up an abandoned checkout flow" or "Write and schedule a welcome series" and it builds the draft for you, in your brand's voice. It never publishes without your OK. ## Steps | Step | Does | |---|---| | Wait | For minutes, hours or days, or until a time of day in their time zone | | If / else | Checks one thing, then runs the Yes steps or the No steps. The two paths do not join again | | Send email | Your email, built from blocks | | Send text | A text from your texting number (when shipped) | | Add tag | Puts a tag on the profile, for If / else steps and for finding people later | | Send to webhook | Posts the profile as JSON to an address you give, signed | | Push to CRM | Sends the profile right away to your connected [CRM or webhook](https://sporetag.com/docs/crm-connectors) (HubSpot, GoHighLevel, Airtable or a webhook), every one or the one you pick, with the fields picked for that tool. Works even if **Start sending** is off there. Needs one connected | | Notify me | Emails you, with a link to the profile | | End | The flow ends here | **If / else can check:** has an email, has a phone, agreed to texts, came from a source, came from an ad platform, came from a campaign, visited a page, reached or did not reach a goal (within some days, or since they entered), is in a segment, is in a stage, spent more than an amount, has a tag. **Their time zone** comes from their email or text tool when it told us one, else from the first country they visited from (a guess), else your site's time zone. ## Email Build an email from blocks: heading, text, button, image and divider. Links in text and buttons are counted when clicked. **Merge fields** fill in for each person: `{first_name}`, `{name}`, `{source}`, `{campaign}`, `{last_page}` and `{site_name}`. Add a fallback after a bar for people you do not know the field for: `{first_name|there}`. Press **Preview** to see it with a sample person, and **Send a test to me** to get it in your own inbox. Every email: - Comes from your **From name**. It is sent from Sporetag's sending address, until you set up [email from your own domain](https://sporetag.com/docs/sending-domain); then it comes from your own address. - Has its own reply address. When someone replies, the reply shows in [Messages](https://sporetag.com/docs/messages), and a copy goes to your **Replies go to** address (your account email when empty). Turn the copy off in **Automations settings**. - Ends with your name, your **postal address** and an **Unsubscribe** link, as the US CAN-SPAM Act asks. A flow with an email cannot go live until the postal address is set in **Automations settings**. - Carries one-click unsubscribe headers, so Gmail and Apple Mail show their own unsubscribe button. - Has a plain-text version. Emails go only to people whose email is stored: **Show contact details** must be on, in the settings of the site's customer profiles. Someone who unsubscribed, from a flow email or in Klaviyo or Mailchimp, is skipped. ## Texts (when shipped) Texts go from your [texting number](https://sporetag.com/docs/texting-number), at 2¢ a part, billed with your plan each month. Until texts are switched on, text steps are skipped and say why. Once they are: - **Consent first.** A text goes only to someone with consent to texts on record: a ticked box about texts on your website form (with form capture on; its words are kept as the record), or a yes in an imported **Agreed to texts** column. Everyone else is skipped. - **Quiet hours.** No texts from 9 pm to 8 am in their time zone. A text due then waits until 8 am. - **STOP works at once.** A reply of STOP (or STOPALL, UNSUBSCRIBE, CANCEL, END, QUIT) stops all texts from that site. START turns them back on. HELP gets a short answer. - **Your brand first.** Each text starts with your brand name, and the first text a person gets ends with "Reply STOP to opt out." - **US numbers need registration.** Carriers block business texts to US numbers from unregistered senders. [Get a texting number](https://sporetag.com/docs/texting-number) registers your brand and campaign (or a toll-free number) for you, with every fee shown first. - The editor counts characters and message parts. A plain text fits 160 characters in one part; emoji and some letters bring that to 70. ## Limits | Plan | Live flows per site | Emails a day per site | Texts a day per site | |---|---|---|---| | Solo | 5 | 500 | 100 | | Studio | 25 | 2,000 | 500 | | Agency | 100 | 10,000 | 2,000 | Set a lower daily limit in **Automations settings**: **Settings** on Automations, or on any flow of the site. A send past the day's limit waits until the next day (UTC), it is not dropped. ## Numbers Each flow in the list shows four numbers: **In it now** (people waiting on a step), **Sent** (emails and texts, last 30 days), **Sales** (last 30 days) and **Last run**. Open a flow for the rest of the last 30 days: how many people **entered** and **completed** it, emails sent, opened and clicked, texts sent, delivered and replied, and **sales**. Each step shows its own counts on the canvas. A sale counts for a flow when the buyer's last flow email or text came within the days you set in settings (5 by default): last touch. The **Attribution** tab shows these sales in a **By automation** table. Opens are counted when the email's images load. Some mail apps load them on their own, so opens run high. Clicks are a better signal. ## Webhooks A **Send to webhook** step posts JSON: the flow, the step, the site and the profile (id, label, email and name when stored, first and latest source, orders and revenue). It is signed: `x-sporetag-timestamp` and `x-sporetag-signature: sha256=` the HMAC-SHA256 of the timestamp, a dot and the body, with the key in **Automations settings**, under **For developers**. Addresses must use https. ## How it runs Steps that are due run every 15 minutes, so a wait of 10 minutes can take up to 25. The first steps of a flow run the moment it starts. Each step is recorded before it acts, so an email or text is never sent twice, even when something is retried. --- # Import your history > Bring past visits in from Google Analytics 4, Plausible or Fathom, so your charts are full on day one. What comes in, and how it is counted. Source: https://sporetag.com/docs/import-history Section: Measure Moving to Sporetag does not mean starting from an empty chart. Bring the days before Sporetag in from the tool you used, and your dashboard shows them next to the days Sporetag tracks. Open your site, then **Settings**. The **Import history** card has both ways in. ## From Google Analytics 4 Connect Google Analytics (when shipped). 1. Click **Connect Google Analytics** and sign in with a Google account that can see the property. Sporetag asks to read your analytics, nothing else. 2. Pick the property and click **Start import**. The import runs on its own, newest days first, and the card shows how far it has come. You can close the page. When it ends, Sporetag gives the Google access back. ## From Plausible 1. In Plausible, open the site's settings, then **Imports and Exports**, and export to CSV. 2. Upload the zip file to the card as it is, and click **Import file**. ## From Fathom Fathom's dashboard download holds totals for the whole range, not each day, so use a custom export: 1. In Fathom, start a new export of **Pageviews**, grouped **Daily**, with all metrics, over the range you want. 2. Export once with no dimension. That file holds the daily totals and is needed. 3. Export once more for each breakdown you want: page, referrer, country, device type, browser, operating system, a UTM field or event name. 4. Upload all the files to the card at once. ## How the days are counted - **No day counts twice.** Only days before your first tracked day come in. From that day on, only Sporetag's own numbers count. The chart marks the day, and a note above it says where the earlier days come from. - **Your plan's history applies.** The import reaches back as far as your plan keeps history, and imported days age out with it. - **Other tools count differently.** GA4 counts a user by a browser cookie, so a GA4 user is not a Sporetag visitor. Visits are GA4 sessions, a bounce is a session GA4 did not count as engaged, and time is the time the page was in front. Imported days will not line up exactly with tracked days. - **Google may hold numbers back.** For privacy, Google leaves out small numbers in some reports (thresholds), and may estimate a report from a sample. The card says so when that happened. - **Goals:** key events from GA4 and custom events from Plausible and Fathom show on a goal with the same event name. Sales, revenue and visitor profiles start with Sporetag. - **Filters** apply to tracked days only. GA4 days follow your property's time zone; Sporetag's follow UTC. ## Import again or remove A new import replaces the days imported before. **Remove imported days** takes them all out. Days Sporetag tracked are never changed by either. --- # Meta ad spend and ROAS > Connect Meta Ads in one click to see what each campaign, ad set and ad cost next to the sales Sporetag credits, with Meta's own numbers beside ours. Source: https://sporetag.com/docs/meta-ads-spend Section: Measure Connect Meta Ads, and the **Attribution** tab shows what each campaign, ad set and ad cost next to the sales Sporetag credited to it. You see return on ad spend (ROAS), cost per purchase, and what Meta says beside what Sporetag saw. Sporetag only reads. It can never change your ads, budgets or audiences. It is on paid plans: Solo, Studio, Agency and Custom. Free does not include it. ## Connect with Meta 1. Open your site, then **Settings**, then **Integrations**. Under **Ad spend**, click **Connect** next to **Meta Ads**. 2. Log in to Meta and allow Sporetag to read your ad results. 3. Back in Sporetag, tick the ad accounts to read. Accounts that spent in the last 90 days are ticked for you. 4. Click **Start**. A progress bar shows the import of the last 90 days. You can leave the page. That is all. After the import, spend updates every hour. ### When the login ends A Meta login can end, often after about 60 days. When it does, the **Meta Ads** row says **Reconnect**. Click **Reconnect Meta** and log in again. Your spend so far is kept, and the sync picks up where it stopped. ## Other ways to connect: a System User token A System User token never ends, which suits agencies with many clients. Open **Other ways to connect** on the Meta Ads page and follow these steps. Meta's screens change from time to time, so the names may differ a little. 1. In Meta, open [Business settings](https://business.facebook.com/settings/system-users), then **Users**, then **System users**. Click **Add**. Name it `Sporetag` and pick the **Employee** role. 2. Click **Assign assets**. Pick **Ad accounts**, tick your ad account and turn on **View performance**. Save. 3. Click **Generate token**. Pick your business app. If you have none, make one first at [developers.facebook.com](https://developers.facebook.com/apps), type **Business**. 4. Set the expiry to **Never** if Meta offers it. Tick the `ads_read` permission, then generate. 5. Copy the token. Meta shows it only once. Paste it in Sporetag and click **Connect**. Sporetag checks that the token has `ads_read` and can see an ad account. It is stored encrypted and never shown again. Already use the [Meta Conversions API](https://sporetag.com/docs/meta-conversions-api) on this site? The page offers **Use the token saved for Meta Conversions API**. It works when that token can also read ad results. ## What Sporetag reads For each ad account you pick, per day: spend, impressions, reach, clicks, and every action Meta reports (signups, leads, purchases, landing page views, link clicks, custom conversions and the rest) with the value Meta puts on them, in the account's currency. It reads campaigns, ad sets and ads, and what each ad set is optimized for. - Numbers follow each ad set's own attribution setting, such as 7-day click and 1-day view, so they match Ads Manager. - Meta reports some actions under two names, like `complete_registration` and `offsite_conversion.fb_pixel_complete_registration`. Sporetag counts them once. - The first import reads the last 90 days. - Each hour after, it reads again from 3 days before the last sync, because Meta updates recent days late. A day read twice replaces itself. It never counts twice. - When Meta asks Sporetag to slow down, the sync pauses and carries on later. It does not show as an error. ## The Ad spend card The card on your dashboard leads with what Ads Manager calls **Results**: what each ad set is optimized for, like **Signups (Meta) 106** and **Cost per signup (Meta) $2.25**. A number Meta reports always says (Meta). A number Sporetag tracked on your site says (tracked). The two are never added together. A cost per action divides only the spend of the platforms that report that action. With Meta and Google both spending, **Cost per signup (Meta)** is Meta's spend over Meta's signups, the same as Ads Manager. Point at a day on the card's chart to see its numbers for that day. Click a number on top, or a day, to open its [breakdown](https://sporetag.com/docs/dashboards#see-what-makes-a-number) by platform, campaign, ad set and ad. Open the card's menu and pick **Customize** to choose: - **Result**: each ad set's own (the default), or one action for every row, like signups. - **Numbers on top**: which ones, in what order. - **Columns**: start from Performance, Signups, Sales or Delivery, then add, remove and order them. Sort by any column. - **Chart**: spend, or any number with a value per day. Reach is added up day by day, so someone reached on two days counts twice. Frequency uses the same reach. ## Matching spend to sales Spend joins the sales Sporetag credits by the tags on each ad's link: 1. **Campaign id first.** Our Meta URL template sends `utm_id={{campaign.id}}`, which matches even after you rename a campaign. 2. **Then names.** `utm_campaign`, `utm_term` and `utm_content` are matched to the campaign, ad set and ad names, written the way the link builder writes them: lowercase, with hyphens for spaces. "Spring Sale" and `spring-sale` match. 3. **Then the click id and the day.** A visit with Meta's `fbclid` but no tags that name an ad goes to the campaign, ad set and ad when only that one had clicks that day and the days either side. With two running, it stays untied: a click id says it came from Meta, not from which ad. When visits from Meta arrive but cannot be tied to an ad, the Ad spend card says so in one line, with **Copy parameters** for the line below. After the import, the Meta Ads page checks your active ads. If some have no Sporetag tags, it shows the one line to paste: ``` utm_source=facebook&utm_medium=paid-social&utm_campaign={{campaign.name}}&utm_content={{ad.name}}&utm_term={{adset.name}}&utm_id={{campaign.id}} ``` In Ads Manager, open the ad, find **URL parameters** under **Tracking**, paste it and publish. You can select many ads and edit them together. More in [Tracking ads with UTMs](https://sporetag.com/docs/tracking-ads-with-utms). ## Reading the numbers On the **Attribution** tab, **Spend and return** has a switch for **Platform**, **Campaign**, **Ad set** and **Ad**. It follows the period and the first touch or last touch switch above it. | Column | What it is | |---|---| | Spend | What Meta charged in the period | | Sales | Purchases Sporetag credited to it | | Revenue | Their value | | ROAS | Revenue divided by spend. 3.0x means $3 back for each $1 | | Cost per purchase | Spend divided by sales | | Meta says | The purchases and value Meta counts itself | Meta and Sporetag count in different ways. Meta counts views and clicks inside its own windows, and models some sales it cannot see. Sporetag counts the sales it saw on your site, your server and your store, credited by first or last touch. Both are useful. A big gap is worth a look. **Spend we could not match to tracked links** lists campaigns with spend but no tracked visit in the period. Most often their ads have no tags. Add the URL template to fix it. ### Currencies The dashboard adds spend up in your reporting currency, converted at the European Central Bank rate for each day (see [Profit, blended ROAS and currencies](https://sporetag.com/docs/profit-and-currency)). This report keeps each currency on its own line, and ROAS shows only where spend and sales use the same currency. Sales sent without a currency count as US dollars, as on the rest of the report. ## Disconnect On the Meta Ads page, click **Disconnect Meta**. Sporetag deletes the saved login and the spend it brought in. Connect again to bring the spend back. --- # Email from your own domain > Send flow emails from you@yourbrand.com (when shipped), with replies on the person's profile and in your inbox. The DNS records, step by step. Source: https://sporetag.com/docs/sending-domain Section: Measure Flow emails can come from your own address, like `you@yourbrand.com`, instead of Sporetag's address with your name. This is "(when shipped)" until Sporetag switches it on. Until then, emails go from Sporetag's address with your name, and replies go to your **Replies go to** address. What you get: - Emails come from your own address. People see your name and your domain. - Replies come back to Sporetag, count on the flow, and go on to your own inbox. To the person, it is a normal reply. - Inboxes trust mail signed by your own domain more, so fewer emails land in spam. You add a few DNS records once. It takes about ten minutes, plus waiting for DNS. ## Step 1: add the domain 1. Open **Automations**, then **Settings** (with more than one site, pick the site). 2. Under **Email from your own domain**, enter your domain, like `yourbrand.com`. It starts with your site's domain. 3. Enter the address to send from, like `you@yourbrand.com`, and the name people see. 4. Choose **Add domain**. Sporetag gets ready for your domain, then shows the records to add. Each record has **Copy** buttons for its name and value. A domain belongs to your account. Every site in your account can use it: pick it under **Send this site's email from**. ## Step 2: add the records | Type | Name | Value | What it does | |---|---|---|---| | CNAME (3 of them) | `._domainkey` | `.dkim.amazonses.com` | Signs your email (DKIM), so inboxes know it is really from you. | | MX | `bounce` | `feedback-smtp..amazonses.com`, priority 10 | Takes bounce reports. | | TXT | `bounce` | `v=spf1 include:amazonses.com ~all` | Lets Sporetag send for you (SPF). | | MX | `reply` | `inbound-smtp..amazonaws.com`, priority 10 | Brings replies back to Sporetag. | | TXT (suggested) | `_dmarc` | `v=DMARC1; p=none;` | Tells inboxes what to trust (DMARC). Skip it if you have one. | The page shows the exact codes and region for your domain. Copy them from there. The values name the mail servers Sporetag sends through, so type them exactly as shown. - The `bounce` and `reply` names are new subdomains just for this. They do not change your normal email. Your own inbox keeps working as it is. - The `bounce` name must have exactly one MX record. The `reply` name needs the mail server above as its only one. - On Cloudflare, set the three CNAME records to **DNS only**, the gray cloud. - Some DNS hosts ask for the priority in its own box. Enter `10`. - If your domain already has a DMARC record, keep yours. The page says when it finds one. The page names your DNS host when it can tell (Cloudflare, GoDaddy, Namecheap, Squarespace and others), with that host's steps and a link to its DNS page. Where your DNS host supports Domain Connect, a button sets everything up in one go. ## Step 3: wait for Verified Opening the page checks each record live, and so does **Check now**. We also check every 15 minutes. Each record shows **Found**, **Different** (with what it holds now) or **Not found yet**. Once the DKIM records are seen, the domain shows **Verified**. That is usually minutes after DNS updates, and at most 72 hours. From then on, the site's flow emails go out from your address. ## Replies Each email has its own reply address on your reply subdomain, like `you+3f9a...@reply.yourbrand.com`. People never type it. They just press reply. When someone replies: 1. Sporetag matches it to the person and the email they got. 2. The flow counts it as a reply. 3. Sporetag forwards it to your inbox, from your own address, with **Reply-To** set to the person. Answer from your inbox, and your answer goes straight to them. Replies go to **Forward replies to**, else **Replies go to**, else your account email. Out-of-office replies, spam and viruses are not forwarded. Replies over 150 KB, usually ones with large attachments, bounce back to the sender: that is the limit for passing mail on. ## Bounces and complaints If an address bounces for good, or someone marks your email as spam, Sporetag stops emailing that address from the site. It is added to the same list as unsubscribes. ## If it does not verify - **Different**: the record holds another value. Change it to the value shown. - **Not found yet**: add the record, or wait. DNS can take up to an hour. - **Failed**: the records were not seen within 72 hours. Check the three DKIM records, then remove the domain and add it again. ## Remove a domain Choose **Remove** on its row. Sites that used it go back to Sporetag's address. You can delete the DNS records afterward. --- # Get a texting number > Your own number for flow texts (when shipped). Sporetag registers it with US carriers for you, shows the price first, and tells you where the review stands. Source: https://sporetag.com/docs/texting-number Section: Measure Flow texts go out from a number that is yours. Sporetag gets it for you and does the carrier registration. This is "(when shipped)" until Sporetag switches texts on. US carriers block business texts from numbers that are not registered. Registration tells them who you are and what you will send. It is the same for every business, and it takes some patience: reviews take days, sometimes a few weeks. ## Pick your path | You have | You get | Registration | |---|---|---| | An EIN (a US business tax ID) | A local number with your area code | Your brand, then your campaign | | No EIN (sole proprietor) | A toll-free number | Toll-free verification | Both can send the same texts. Open **Get a texting number** from your Automations settings, or go to `/app/texting`. ## Prices The same on both paths: | Usage | Price | |---|---| | Texting setup, once | $25 | | Texting number | $5 a month | | Texts | 2¢ a part | Texting setup covers the carrier registration. A part is up to 160 characters, or 70 with emoji; long texts count as 2 or more. Billed with your plan each month. What you used shows under **Usage** in Billing. ## Fill in your details The form starts with what we know from your account. It asks for: - **Your business**: the legal name exactly as on your tax forms, the type, your EIN, your industry and website. - **Address**: where the business is registered. - **Contact person**: someone the carriers can reach, with their job title. - **Your texts**: what you text about, two real sample texts, and how people agree to get them. What carriers look at most: - **Samples** name your brand and say how to opt out, like "Reply STOP to opt out." - **How people agree** is specific: the page, the checkbox, and what it says. A checkbox that is ticked for people is not consent. - Your **website** works and shows the same business name. Tick the box to agree to the prices, then choose **Submit registration**. Your details are stored encrypted and used only for the carrier registration. ## Where it stands The page shows each stage: 1. **Business profile**: we check your details. 2. **Brand**: the carriers' registry checks your business. 3. **Campaign**: the carriers check what you will text. 4. **Number**: you pick it. We check every 15 minutes. **Check now** asks at once. If something is turned down, the page shows the reason the carriers gave. Fix it with **Start over with new details**, or choose **Try again** if it was a passing problem. ## Pick your number Once the campaign is approved (or right away, on the toll-free path), enter an area code and pick a number. It is set up and attached for you. Every site in your account that has no texting sender yet starts using it. You can change each site's sender in its Automations settings. On the toll-free path, verification starts once you have the number. Texts can go out once it is approved. ## Replies and STOP Replies come back to Sporetag. STOP, START and HELP work at once, on every site that uses the number. See [Automations](https://sporetag.com/docs/automations) for the texting rules: consent, quiet hours and the opt-out line. --- # Call tracking > Tracking numbers that show which ad, search or flyer made the phone ring (when shipped). Calls count as goals, join the caller's profile and reach your ads. Source: https://sporetag.com/docs/call-tracking Section: Measure Many customers call instead of filling in a form. Call tracking gives you phone numbers that ring your real phone and tell Sporetag where each caller came from. It is on Solo, Studio and Agency, and "(when shipped)" until Sporetag switches calls on. Open your site's **Settings**, then **Integrations**, and tap **Set up call tracking**. It takes two steps. Once the site has a number, it gets its own **Calls** tab. ## 1. Where calls ring Enter the number your phones ring on today. Every tracking number forwards here. Callers hear ringing as usual, and your phone shows their own number, so you can call them back. Then list the numbers your website shows, up to three. Leave it blank if your website shows the same number. ## 2. Pick your numbers | Kind | What it is for | How it counts calls | |---|---|---| | Numbers for your website | Your site shows each visitor their own number, in place of yours | A call is tied to that visit: its source, campaign, ad and click ids | | A number for one place | A flyer, a truck, Google Business Profile, an ad's call button | Every call to it counts for that place, by the name you give it | Pick local numbers with an area code, or toll-free numbers. You see the price before you get anything. Calls need no carrier registration, so a number works as soon as you get it. ## Prices | Usage | Price | |---|---| | Phone number, local or toll-free | $3 a month | | Calls, recording included | 5¢ a minute | Each call counts its started minutes, so a 61-second call is 2 minutes. Billed with your plan each month. What you used shows under **Usage** in Billing. ## How numbers on your website work Sporetag's tag already loads the swap once you have website numbers. There is nothing to add to your site. - The swap looks for your listed numbers in `tel:` links and in the words on the page. It keeps the way you wrote the number, like (503) 555-0142 or 503.555.0142. - It only asks for a number on pages that show yours, so the pool is not used up by pages with no number. - If no number comes back, your own number stays. A call to it still reaches you; it just has no source. - Each visitor keeps their number for 30 minutes after their last page or tap. How many numbers you need depends on how many visitors look at your site at the same moment. Four suits most small businesses, and a pool holds up to ten. When every number is in use, the one idle longest goes to the new visitor, and a call on it counts for the newest visit. The Calls tab tells you when this happened this week and how many numbers to add. A number split across tags, like `503 555 0142`, or drawn in an image, is not swapped. Write it as plain text or a `tel:` link. ## What a call becomes - **Phone call**: every answered call. It is a goal, so it shows on your dashboard, in reports, in the attribution report and in Autopilot. - **Phone lead**: an answered call of 60 seconds or more. Change the length in the Calls tab settings. - Missed calls are listed in the call log but are not goals. Both goals are added for you when you get your first number, if your plan has room for them. With [90-day tracking](https://sporetag.com/docs/tracking-modes) on, the caller's number finds or makes their [profile](https://sporetag.com/docs/customer-profiles), and the call joins it, with its length, where it came from and whether they called before. The same stream shows in [Messages](https://sporetag.com/docs/messages). The number is kept encrypted, and only while **Show contact details** is on. Automations can start on the Phone call or Phone lead goal. To send phone leads to Google Ads, Meta and your other ad accounts, tick **Phone lead** under **What to send**, in **Settings**, **Integrations**. See [Send results to your ad accounts](https://sporetag.com/docs/send-results-to-ad-accounts). ## The call log The Calls tab shows calls by source and the latest 50 calls: when, where from, the caller's area code and last two digits, first call or not, and how long it lasted or that it was missed. The dashboard has a **Phone calls** widget, and client reports a **Phone calls** block. ## Whisper When you answer, you hear "Call from Google Ads." before the caller is put through. The caller does not hear it. Turn it off in the settings. ## Recording Recording is off unless you turn it on. When it is on: - every caller hears "This call may be recorded." before they are put through; - whoever answers hears "This call is recorded." in the whisper; - the recording plays in the call log for you, never on shared dashboards or reports, and you can delete it. Deleting it, or archiving the site, deletes it everywhere it is stored. Some states, like California, Florida, Illinois, Pennsylvania and Washington, need everyone on a call to know it is recorded. The two notices tell both sides. You are still responsible for following the rules where you and your callers are. This is not legal advice. ## Privacy - The swap sets no cookies and uses no storage. - A visitor whose browser sends [Global Privacy Control](https://sporetag.com/docs/data-and-privacy) keeps no ad click ids with their number, and their calls are never sent to ad platforms. Your own stats still count them. - The call log never shows a full caller number. --- # Import ad spend from a file > Bring spend from Google Ads, TikTok, Microsoft, LinkedIn, Pinterest, Snapchat or any platform as a CSV file or a Google Sheets paste, to see return on ad spend. Source: https://sporetag.com/docs/csv-spend-import Section: Measure Any ad platform can bring its spend into Sporetag as a file. Sporetag then shows return on ad spend (ROAS) for it on the **Attribution** tab, next to the sales it credited. This is also how Google Ads spend comes in until its one-click connect ships (when shipped). It is on paid plans: Solo, Studio, Agency and Custom. Free does not include it. ## Import a file 1. Open your site, then **Settings**, then **Integrations**. Under **Ad spend**, click **Import a file**. 2. Pick the **Platform** if your file has no platform column, like a Google Ads report. 3. Pick the file and click **Import**. Or open **Paste from Google Sheets**, select the cells in your sheet with the header row, copy and paste. Sporetag says how many rows it added, and lists any line it could not read with what to fix. Fix those lines and import the whole file again. A row with the same date, platform, campaign, ad set and ad replaces the one already there, so nothing counts twice. ## Columns Start from **Download the template** on the import page. The first row names the columns. Their order does not matter. | Column | Needed | Example | |---|---|---| | `date` | Yes | `2026-10-01` or `10/1/2026` | | `platform` | Yes, or pick one on the page | `google`, `tiktok`, `microsoft`, `linkedin`, `pinterest`, `snapchat`, `meta` or `other` | | `campaign` | Yes | `Spring sale` | | `ad set` | No | The ad set or ad group | | `ad` | No | The ad name | | `spend` | Yes | `125.40` | | `currency` | Yes | `USD` | | `campaign id` | No | The platform's campaign id. Matches `utm_id` best. | | `impressions`, `clicks` | No | Whole numbers | Common names from platform reports work too: `Day`, `Campaign name`, `Ad group`, `Cost`, `Amount spent`, `Currency code`, `Impr.`. - One row per day and campaign (or ad set, or ad). Add up duplicates into one row. - Dates up to two years back. No future dates. - Spend in the ad account's own currency, as the platform bills it. The dashboard converts it to your reporting currency. - Meta or Google Ads connected? Leave their rows out. Their spend comes in by itself, and the import refuses those rows so nothing counts twice. ## Google Ads 1. In Google Ads, open **Campaigns**. Pick the date range. 2. Click **Segment**, then **Time**, then **Day**. 3. Make sure the columns include **Campaign**, **Cost** and **Currency code**. Add **Campaign ID** for the best match. 4. Click **Download** and pick **.csv**. 5. In Sporetag, pick **Google Ads** as the platform and import the file. The title lines and the total row at the end are skipped for you. For ad group or ad detail, download the same report from **Ad groups** or **Ads**. ## TikTok, Microsoft and others Export a report by day with the campaign name, cost and currency, then import it with that platform picked. If the report has no currency column, add one to the file. The platform's help pages name the report screens. ## Matching spend to sales Spend joins the sales Sporetag credits by the tags on each ad's link: by campaign id (`utm_id`, or Google's `{campaignid}`) first, then by names. `utm_campaign`, `utm_term` and `utm_content` are matched to the campaign, ad set and ad, written the way the link builder writes them: lowercase, with hyphens for spaces. So "Spring Sale" in the file matches `spring-sale` on the link. Campaigns with spend but no tracked visit show as **spend we could not match to tracked links**. Add the platform's URL template to those ads. See [Tracking ads with UTMs](https://sporetag.com/docs/tracking-ads-with-utms). ## Delete imported spend The import page lists what came in, per platform. Click **Delete** next to a platform to remove all its imported spend. --- # Messages > One inbox for every site: replies to your flow emails and texts, what was sent and how it did, each person's stage, and writing back. Source: https://sporetag.com/docs/messages Section: Measure **Messages** in the sidebar is one inbox for all your sites. It holds what your [automations](https://sporetag.com/docs/automations) send and the replies that come back. It comes with Automations, on Solo, Studio and Agency. ## Inbox The **Inbox** tab lists each conversation, newest first: the site, the person, their [stage](#stages), the last message and when it came. A number shows how many messages you have not read. The same number shows next to **Messages** in the sidebar. It holds: - **Text replies.** Anything someone texts back to your texting number (when shipped). STOP shows as an opt-out, START as opting back in, HELP as a request for help. - **Email replies.** Every flow email has its own reply address. A reply lands here, with the old quoted email and the signature cut off. - **Out-of-office replies.** Kept, marked **Auto-reply**, never counted as unread or as someone engaging. - **Requests to stop.** A reply that says "unsubscribe" or "remove me" is marked **Asks to unsubscribe**. Press **Unsubscribe them** to stop all email to them from that site, or **Not an opt-out** to keep it as a normal reply. Words alone never unsubscribe anyone, since "do not stop sending me deals" is not a request to stop. A copy of each email reply also goes to the site's **Replies go to** address (your account email when empty), so nothing waits in Sporetag alone. Turn the copy off in the site's **Automations settings**. Filter by site and stage, or search by name, email or phone number. ## Sent The **Sent** tab lists the last 30 days of emails and texts, from flows, campaigns and your own replies. Each shows its status: | Status | Means | |---|---| | Sent | It left. For email, nothing more is known yet | | Delivered | The carrier says the text reached the phone | | Opened | The email's images loaded. Some mail apps load them on their own, so opens run high | | Clicked | They clicked a link in the email | | Replied | They wrote back | | Failed | It did not send, or the carrier refused the text. The reason shows under it | Email bounces are (when shipped): Sporetag's email sending does not report them yet. ## A conversation Press a conversation to see everything about that person in one stream, oldest at the top: emails and texts both ways, and their visits, pages, goals, forms, orders, CRM deal stages and the flows they entered. **All**, **Messages** and **Activity** filter it. The same stream is on their profile page. At the bottom, write to them: - **Text** works once texts are switched on (when shipped), they agreed to texts, they have not replied STOP, and it is not 9 pm to 8 am their time. The first text you send them ends with "Reply STOP to opt out." - **Email** goes from your site's sender, with your footer, postal address and unsubscribe link. It needs your postal address in **Automations settings**, and they must not have unsubscribed. When a channel cannot be used, it is greyed out and says why. Once the site's flows and replies reach its daily email or text limit, replies on that channel are off until the next day (UTC). ## A new message To write to someone who has not written to you, press **New message** on Messages, or **Send a message** at the top of their profile. 1. Search by name or email. Only people with an email on file show, from all your sites; the message goes from the site the person belongs to. 2. Add a subject and your message, then press **Send**. It goes the same way as an answer in a conversation: from your site's sender, with your footer, postal address and unsubscribe link, and only if they have not unsubscribed and the site has not reached its daily email limit. Then the conversation opens, with your email in it. Texts (when shipped). ## Stages Each profile has one stage, worked out from what Sporetag already knows. It shows on the profile, in the Profiles list and in Messages. The first that fits wins: | Stage | Means | |---|---| | Visitor | Anonymous. Only their device is known | | Unsubscribed | Opted out of email or texts, with no way left to reach them | | At risk | A customer with no visit, open, click or reply in 60 days | | Repeat | Bought 2 or more times | | Customer | Bought once, or won as a deal in your CRM | | Engaged | Opened, clicked or replied in the last 14 days, or came back to your site in the last 14 days | | Lead | Gave an email or phone. Nothing more yet | Opens count toward Engaged even though some mail apps open mail on their own. Out-of-office replies never count. Use stages to act: - In **Profiles**, press a stage to see only those people, with counts for each. - **Send a message** emails everyone in that stage once (a campaign, up to 1,000 people). People who unsubscribed or have no email are left out, and each send is checked again when it goes. Sending starts within 15 minutes and keeps to your daily email limit. - **Add to automation** starts a live flow for them (up to 150 at a time). The flow's own rules apply: someone already in it is not added twice. - In a flow, start it when someone **enters a stage**, or check **Is in a stage** in an If / else step. - In a [segment](https://sporetag.com/docs/segments-and-best-send-time), pick a stage as one of its rules. --- # Short links > Make short links on your own go. domain or go.sporetag.com, track each place you share them, and follow each click to the visit and the sale. Source: https://sporetag.com/docs/short-links Section: Short links A short link is a short address that sends people on to a long one. Sporetag counts each click. When the link leads to a site you track, it also shows the visits and goals that came after the click. ## Make a link 1. Open **Links** and choose **New link**. 2. Paste your link, the page people should land on. 3. Pick where you will share it: SMS, Email, Instagram bio, Meta ads, QR code and more. The tracking fills in for you. 4. Check the **Campaign name**. It starts from the link's name, or from your last campaign. 5. Choose **Make link**. Next you see your link with a big **Copy link** button. You can also copy the full link for ads, download the QR code, or make the same link for other places in one tap. You need a confirmed email to make links. That is one of the ways we keep the shared domain free of spam. ## Your domain New links get six random letters and numbers, like `go.sporetag.com/a8Kd2Q`. On paid plans you can choose your own ending, like `go.sporetag.com/spring`. A few words are reserved and cannot be used. Use your own domain, like `go.yourbrand.com/spring`, on any paid plan. People, Meta, Instagram and email filters trust your own name more. New links start on it once it is verified. See [Custom short domains](https://sporetag.com/docs/custom-short-domains). ## Tracking, made simple Each place you pick fills in the tracking tags for you, in one style: lowercase with hyphens. Anything you type is tidied the same way, so `Spring Sale` becomes `spring-sale` and your reports group it. The tags themselves sit under **Advanced (UTM fields)**. You rarely need to open it. See [UTM presets](https://sporetag.com/docs/utm-presets) for what each place sets, and save your own. If you paste a link that already has UTM tags, they move into the fields. Other parts of the address stay as they were. ## Short link or full link - **Short link**: for SMS, bios, stories, DMs, email and QR codes. It is short, it counts each click, and you can change where it goes. - **Full link**: for ads. The ad opens your page directly, with the tags on it. Copy it with **Copy full link** on the link's page. For per-ad tracking in Meta, Google, TikTok and Microsoft ads, see [Tracking ads and email](https://sporetag.com/docs/tracking-ads-with-utms). ## Follow the click to the sale When the destination is on a site in your account, the redirect adds `_st` and the link id to the address. The script reads it on the landing page, then removes it from the address bar. Goals that visitor reaches later that day count for the link. In [90-day tracking](https://sporetag.com/docs/tracking-modes) the link keeps the credit for 90 days. ## Ad clicks pass through When Instagram or Facebook opens your short link, it adds `fbclid` to it, even on a post you did not pay for. The redirect passes it on to your page, so Meta and the [attribution report](https://sporetag.com/docs/attribution-report) still see the click. The same goes for these ad click ids: `fbclid`, `gclid`, `gbraid`, `wbraid`, `msclkid`, `ttclid`, `twclid`, `li_fat_id`, `rdt_cid`, `ScCid` and `epik`. A click id already in your link stays as it is. Everything else added to a short link is dropped, so nobody can change where it goes. ## Link stats Each link shows: - Clicks over time. - Where the clicks came from, by referrer. - Countries and devices. - For a tracked site: the visits and goals that followed. ## Variants One offer often goes to many places. On the link's page, tick the places under **Make variants** and choose **Make variants**. Each one gets its own short link and tags. The group shows the total, with a row for each place. ## Safety checks Every destination is checked when you save it: - It must start with `http://` or `https://`. - It cannot hold a username or password. - It cannot be another link shortener or redirector. - It is checked against Google Safe Browsing. Links are checked again at least once a day. A link that turns up on a blocklist is turned off and answers with a short error instead of redirecting. ## Archive Archive a link you no longer use. It stops counting toward your active link limit, and its stats are kept. --- # UTM presets > Pick where you will share a link, like SMS, email, Instagram or Meta ads, and the UTM tags fill in. What each place sets, and how to save your own presets. Source: https://sporetag.com/docs/utm-presets Section: Short links UTM tags are short labels on the end of a link, like `?utm_source=instagram`. Analytics tools, Sporetag included, read them to tell you where a visit came from. Typing them by hand is slow and easy to get wrong. When you make a link, you pick where you will share it and the tags fill in. ## What each place sets | Place | utm_source | utm_medium | utm_content | |---|---|---|---| | SMS | `sms` | `sms` | | | Email | `newsletter` | `email` | | | Instagram bio | `instagram` | `social` | `bio` | | Instagram story | `instagram` | `social` | `story` | | TikTok bio | `tiktok` | `social` | `bio` | | Facebook post | `facebook` | `social` | `post` | | Meta ads | `facebook` | `paid-social` | | | Google Ads | `google` | `cpc` | | | TikTok Ads | `tiktok` | `paid-social` | | | Microsoft Ads | `bing` | `cpc` | | | LinkedIn Ads | `linkedin` | `paid-social` | | | Pinterest Ads | `pinterest` | `paid-social` | | | Snapchat Ads | `snapchat` | `paid-social` | | | QR code | `qr` | `qr` | | | Print | `print` | `print` | | The campaign name, `utm_campaign`, starts from the link's name, like `spring-sale`. With no name, it uses the campaign of your last link. Change it any time. ## One style for every value Sporetag keeps every value lowercase, with hyphens for spaces. `Spring Sale!` becomes `spring-sale`. That way `Instagram` and `instagram` never show up as two sources. Ad platform placeholders, like `{{campaign.name}}`, are kept exactly as typed. ## Plain names The form uses plain names. The tags behind them: - **Campaign name** is `utm_campaign`. - **Which ad or post** is `utm_content`. - Under **Advanced (UTM fields)**: **Where it is shared** is `utm_source`, **Kind of traffic** is `utm_medium`, and **Ad set or keyword** is `utm_term`. ## Save your own presets Fill in the tags you use often, open **Advanced (UTM fields)**, give them a name and choose **Save preset**. The preset saves the five tags and the client, if you set one. It shows as a chip next time, under **Yours**. Saving with the same name again replaces it. Manage your presets from the **Manage** chip. ## One offer, many places Make one link, then tick more places under **Make variants** on its page. Each variant gets its own short link and tags, with the same campaign. The group adds them up, so you see the whole offer and each place. ## Where tags show up Open the site's dashboard and look at the Sources panel: UTM source, medium, campaign, ad and ad set. Filter by any of them to see the pages and goals for that traffic only. The [attribution report](https://sporetag.com/docs/attribution-report) shows sales by campaign, ad and ad set too. --- # QR codes > Every Sporetag short link has a QR code you can download as an SVG. Use the QR code preset so scans show up apart from clicks in your stats. Source: https://sporetag.com/docs/qr-codes Section: Short links Every short link has a QR code. Scanning it opens the short link, so each scan counts like a click. ## Download it Open the link and choose **QR code**. Download it as an SVG. SVG stays sharp at any size, from a sticker to a poster, and print shops accept it. ## Tell scans from clicks Make a variant of the link with the **QR code** preset, and print that one. Its visits carry `utm_medium=qr`, so the dashboard shows scans apart from taps on the same link elsewhere. See [UTM presets](https://sporetag.com/docs/utm-presets). ## Print it well - Leave a clear margin around the code, at least the width of four of its small squares. - Print dark on light. Light codes on dark paper scan badly on some phones. - Test a print with two or three phones before a big run. ## If the destination changes The QR code holds the short address, not the destination. Edit the link's destination and every printed code goes to the new place. Nothing needs to be reprinted. Keep the link active as long as the print is out in the world. An archived link stops redirecting. --- # Custom short domains > Put your short links on go.yourdomain.com, a go subdomain of your own site. Step by step for Cloudflare and any other DNS host, plus a Meta tip. Source: https://sporetag.com/docs/custom-short-domains Section: Short links Your short links can live on your own domain: `go.yourdomain.com/spring` instead of `go.sporetag.com/spring`. We suggest a `go` subdomain of the site you already have. Why it helps: - People trust a link more when they know the name. - Links on your own domain are trusted more by Meta, Instagram and email filters. A shared short domain carries everyone's reputation. - Your links stay apart from everyone else's. `go.sporetag.com` works the moment you sign up, on every plan. Add your own domain when you are ready. Solo includes 1 custom short domain, Studio includes 5 and Agency includes 20. Free uses `go.sporetag.com` only. ## Before you start - Pick `go.yourdomain.com`, where `yourdomain.com` is your own site. The `go` subdomain is used only for redirects. It cannot also show a website. - Use a subdomain, not your main domain. Most DNS hosts cannot point a main domain like `yourdomain.com` this way. - You need to sign in where your domain's DNS is managed. That is often where you bought the domain, or Cloudflare. ## Step 1: add the domain in Sporetag 1. Open **Settings** and find **Custom short domains**. 2. Enter `go.yourdomain.com` and choose **Add domain**. If you have a site in Sporetag, the box starts with `go.` and that site's domain. 3. Sporetag shows the record to add. Keep the page open. ## Step 2: add one CNAME record Every DNS host asks for the same three things: | Type | Name | Target | |---|---|---| | CNAME | `go` | `go.sporetag.com` | Some DNS hosts want the full name, `go.yourdomain.com`, instead of `go`. Some call the target **Value**, **Points to** or **Content**. ### On Cloudflare 1. Open your domain in the Cloudflare dashboard, then **DNS** and **Records**. 2. Choose **Add record**. 3. Set **Type** to `CNAME`, **Name** to `go` and **Target** to `go.sporetag.com`. 4. Set **Proxy status** to **DNS only**, the gray cloud. 5. Choose **Save**. DNS only lets the request reach Sporetag directly, so Sporetag can check the domain and get its certificate. ### On any other DNS host 1. Sign in where you manage your domain's DNS. Look for **DNS**, **DNS records** or **Advanced DNS**. 2. Add a new record of type `CNAME`. 3. Enter `go` as the name or host, and `go.sporetag.com` as the target or value. 4. Leave the TTL as it is, or pick the shortest one. 5. Save. If there is already a record for `go`, remove it first. A name can have only one CNAME record. ## Step 3: wait for Active Back in **Settings**, the domain shows **Setting up** with a live check of its record. Opening the page checks it, and so does **Check now**. We also check every 15 minutes. The check says one of: - **Record not found yet.** Add the record, or wait. DNS can take up to an hour. - **Found, pointing to** something else. Change the record to the target shown. On Cloudflare, an address here usually means the proxy is on: set the record to **DNS only**. - **Found and correct.** We get the HTTPS certificate next. It usually takes a few minutes. Settings also names your DNS host when it can tell (Cloudflare, GoDaddy, Namecheap, Squarespace and others), with that host's own steps and a link to its DNS page. Once it shows **Active**, the HTTPS certificate is issued and the domain is ready. You do not need to set up a certificate yourself. ## More than one domain Add as many as your plan has room for, on any subdomain you like: `go.`, `links.`, `l.` and so on. Each one gets its own row, its own record and its own check. Once a domain is Active its row folds to one line. ## Use it New links start on your default domain. Choose **Make default** next to any Active domain, or next to `go.sporetag.com`. Until you choose, new links start on your first Active domain. You can still pick another in the **Domain** list on each new link. The links list shows your domains at the top, with how many links each one has. ## Tip: verify your domain with Meta If you run Meta ads, verify `yourdomain.com` in Meta Business Settings, under **Brand safety** and **Domains**. Meta then knows the domain is yours. You verify the main domain, and Meta counts its subdomains, like `go`, as part of it. Verifying is done in Meta, not in Sporetag, and it is free. ## What the domain serves A short domain only does redirects: - `/your-link` sends people to the link's page. - A link that was turned off answers with a short error. - The bare domain sends people to sporetag.com. - Anything else answers "Not found". It never shows a page, a sign in form or a file. That keeps it hard to misuse. ## Remove it Archive the links that use the domain, then choose **Remove** next to it in **Settings**. Then delete the CNAME record. Links on that domain stop working once it is removed. --- # Tracking ads and email > Track each ad in Meta, Google, TikTok and Microsoft ads with copy-ready templates, and SMS and email with the right link. Naming rules included. Source: https://sporetag.com/docs/tracking-ads-with-utms Section: Short links This page shows how to see which ad, email or text brought each visit and sale. Sporetag fills in most of it for you. You copy one thing and paste it in one place. ## Short link or full link - **Short link**: use it for SMS, bios, stories, DMs, email and QR codes. It is short, it counts every click, and it works on your own domain. - **Full link**: use it in ads. The ad opens your page directly, with no extra redirect. Ad platforms check where an ad leads, and a direct link keeps that simple. Both carry the same tags, so your stats line up. ## Naming rules Sporetag uses one style, and tidies what you type to match it: - Lowercase, with hyphens for spaces: `spring-sale`, not `Spring Sale`. - `utm_source` is the platform: `facebook`, `google`, `tiktok`, `newsletter`, `sms`. - `utm_medium` is the kind of traffic: `social`, `paid-social`, `cpc`, `email`, `sms`, `qr` or `print`. - `utm_campaign` is the campaign, like `spring-sale`. - `utm_content` is the ad or the spot, like `bio`, `story` or the ad name. - `utm_term` is the ad set or the keyword. The [attribution report](https://sporetag.com/docs/attribution-report) shows sales by campaign, by ad (`utm_content`) and by ad set or keyword (`utm_term`). ## Meta ads Pick **Meta ads** when you make a link, then copy the template: ```text utm_source=facebook&utm_medium=paid-social&utm_campaign={{campaign.name}}&utm_content={{ad.name}}&utm_term={{adset.name}}&utm_id={{campaign.id}} ``` 1. In Ads Manager, open your ad. Put your page address in **Website URL**, not the short link. 2. Under **Tracking**, find **URL parameters** and paste the template. 3. Publish. Meta fills in the campaign, ad set and ad names for each click. Meta reads the names when the ad is published. If you rename an ad later, publish it again to see the new name. Meta also adds `fbclid` to the address, which Sporetag reads. ## Google Ads ```text utm_source=google&utm_medium=cpc&utm_campaign={campaignid}&utm_content={creative}&utm_term={keyword} ``` 1. In Google Ads, open the settings of your account or campaign and find **Final URL suffix**. 2. Paste the template. Keep **auto-tagging** on: it adds `gclid`, which Sporetag reads too. 3. Save. Google fills in the campaign id, the ad and the keyword. ## TikTok Ads ```text utm_source=tiktok&utm_medium=paid-social&utm_campaign=__CAMPAIGN_NAME__&utm_content=__CID_NAME__&utm_term=__AID_NAME__&utm_id=__CAMPAIGN_ID__ ``` 1. In TikTok Ads Manager, open your ad and find **Destination**. 2. Under **URL parameters**, paste the template. Keep the capital letters: TikTok only reads them that way. 3. Submit. TikTok fills in the campaign, ad group and ad names. It also adds `ttclid`, which Sporetag reads. ## Microsoft Ads ```text utm_source=bing&utm_medium=cpc&utm_campaign={Campaign}&utm_content={AdId}&utm_term={keyword}&utm_id={CampaignId} ``` 1. In Microsoft Advertising, open the settings of your account or campaign and find **Final URL suffix**. 2. Paste the template. Keep the Microsoft Click ID (`msclkid`) on. Turn off Microsoft's own UTM tagging, which can replace these values. 3. Save. Microsoft fills in the campaign, ad and keyword. ## LinkedIn, Pinterest and Snapchat Pick the platform and copy the full link as the ad's destination. LinkedIn Campaign Manager can also add dynamic UTM tags for you, set once for the account. For Pinterest and Snapchat dynamic values, check each platform's ads help. Sporetag reads their click ids: `li_fat_id` (LinkedIn), `epik` (Pinterest) and `ScCid` (Snapchat). ## SMS Pick **SMS**. Sporetag makes the shortest link it can: your own `go.` domain with six random characters. The result shows the link and how many characters it takes. SMS tools such as Attentive, Postscript and Klaviyo often shorten links again with their own domain, so they can count clicks. Then two redirects run: theirs, then yours. Both still work. To keep only your link: - Turn off the tool's link shortening or click tracking for that message, if it lets you. In Klaviyo, this is the **Automatically shorten links** option on an SMS message. - Or accept the double redirect. Your Sporetag stats still count the click. Each tool names these settings a little differently, so check its help pages. ## Email Pick **Email**. Use the short link in the email: it is tidy, it counts clicks, and Sporetag's tags always win, because the short link ignores anything added to it. Many email tools add their own UTM tags to every link. On a short link that does no harm. On a full link, the tool may replace your tags or add a second set, depending on the tool. Turn its tags off, or set it to use the same names as above. To fill the campaign in per send, use the full link with your email tool's merge tags instead of a short link. A short link cannot carry merge tags. For Mailchimp, pick **Email** and copy the template: ```text utm_source=newsletter&utm_medium=email&utm_campaign=*|CAMPAIGN_UID|* ``` Mailchimp fills in the campaign id when it sends. Klaviyo can add UTM tags to every link from its UTM tracking settings, with the campaign name as a value. Merge tags differ by tool, so check your tool's docs for the exact tag. ## Check that it works Click your own ad preview, text or email link. Then open your site's dashboard. The Sources panel shows the visit under the campaign, the ad and the ad set or keyword. --- # Client dashboards > Share a read-only dashboard by private link or invite clients by email to sign in with no password. Agency makes it white label. Source: https://sporetag.com/docs/client-dashboards Section: Clients A client dashboard is a read-only copy of a site's stats. Share it two ways: a private link anyone can open, or an invite by email, where your client signs in with no password. Either way, they cannot change anything. Client dashboards are part of the Studio and Agency plans. ## Make one 1. Open the site, then **Reports**, then **Share**. 2. Turn on **Client dashboard**. 3. Copy the link and send it to your client. The link looks like `sporetag.com/share/` followed by a long random token. Anyone with the link can see the stats, so share it only with people who should. ## Invite a client by email An invite is safer than a link: only that person can open the dashboard, and you can take it back at any time. 1. Open the site, then **Reports**, then **Share**. 2. Under **Invite a client by email**, type your client's email and press **Send invite**. 3. Your client gets an email with one button. Pressing it signs them in. There is no password to set. The button works once, for 7 days. Later, your client signs in at `sporetag.com/login` with **Email me a sign-in link**, or with **Continue with Google** when their Google account uses the same email. Signed in, your client sees a short list of the sites shared with them, and each site's read-only dashboard. It opens in the [simple view](https://sporetag.com/docs/autopilot#the-simple-view-for-clients): big numbers and plain words, with a button to the full dashboard. To start a client on the full dashboard, press **Show full dashboard** next to them under **Simple view** on the **Share** tab. They do not see billing, settings, your other sites or anything else of your account. A site can be shared with up to 25 people by email. **Send again** sends a new button and stops the old one. **Revoke** ends their access at once, even if they have the dashboard open. You need to confirm your own email before you can send invites. ## Ask your client to connect their ad account Your client can connect their own Meta Ads account to the site, so you see ad spend next to sales without their password and without sharing your Sporetag login. 1. Invite your client by email first. 2. Under **Ask your client to connect ads**, pick who to send it to, then press the button. Or choose to send the link yourself and copy it. 3. Your client opens the link, reads what will be shared, logs in on Meta's own page and ticks the ad accounts to share. Sporetag only reads ad spend and results. Meta asks your client to allow the `ads_read` permission, which cannot change ads. The connection shows on the site's **Integrations** page (under **Settings**) as "Connected by" and your client's email. Your client can disconnect it from the same link at any time, which deletes the login and the spend it brought in. Only people you invited to that site can use the link. It works once, for 7 days, and you can remove it before then. Google Ads works the same way once Google approves Sporetag (when shipped). ## What it shows The same numbers you see: visitors, pageviews, bounce rate, visit duration, conversions, the chart and the lists of pages, sources, campaigns, countries and devices. The period menu works too. It does not show your other sites, your links or your settings. ## Your logo Studio and Agency put your logo on the client dashboard and on [weekly reports](https://sporetag.com/docs/weekly-reports). Upload it in **Settings**. A square or wide logo on a clear background looks best in both light and dark. ## White label On Agency, the client dashboard shows only your brand. There is no Sporetag header, footer, name or link. Set your brand name in **Settings**, next to your logo. The page then shows your logo, or your name when there is no logo. Invite emails on Agency come from your brand name, with your logo or name at the top and no Sporetag letterhead. The sending address is still `hello@sporetag.com`, and the button links to `sporetag.com`. On Studio, invites come from Sporetag on your behalf. ## Turn it off Turn off **Client dashboard**, or make a new link. The old link stops working at once. People you invited by email keep their access until you revoke it. If your plan moves below Studio, client dashboards close, both the link and the invites. ## Labels for many clients Give each site a client label in its settings, such as the client's name. The sites list can then show one client's sites at a time. --- # Client reports > Build an email report from your dashboard's numbers, charts and ads, then send it to clients weekly, monthly or both. Source: https://sporetag.com/docs/client-reports Section: Clients A client report is an email with a site's numbers. You build it from the same charts and numbers as your dashboard, add a few words, and Sporetag sends it on a schedule. Your clients see ad spend, sales and visits without logging in anywhere. Client reports are part of the Studio and Agency plans. Or ask the [assistant](https://sporetag.com/docs/assistant), like "Make a weekly ads report for my client". It proposes the report with its schedule on a card; you add client addresses there and press **Apply**. ## Make one 1. Open the site, then **Reports**. 2. Under **New report**, pick a template: | Template | What it holds | Sent | |---|---|---| | Weekly ads report | Spend, revenue from ads, ROAS, cost per sale, campaigns and platforms | Mondays, for last week | | Monthly performance | Visitors, conversions, revenue, spend, top sources and pages, goals, ad spend | The 1st, for last month | | Ecommerce summary | Revenue, orders, conversion rate, ROAS, sales by store, where buyers came from | Mondays, for last week | | Lead gen summary | Conversions, conversion rate, cost per lead, spend, goals, campaigns and sources | Mondays, for last week | | Blank | A heading and a short note | Mondays, for last week | 3. Change anything you like, then click **Save**. A site can have up to 20 reports. **Duplicate** copies one, paused, so it does not send twice while you change it. ## Build it A report is one column of blocks, top to bottom. Click a block to open its settings. Use the arrows to move it, and the bin to remove it. **Add block** adds one under the block you have open. Numbers and charts work as they do on the [dashboard](https://sporetag.com/docs/dashboards): pick a metric (website, sales, ads or email and texts, for all platforms or one), rows, a filter, and for ad tables which campaigns show, the sort, the columns and how many. | Block | What it shows | |---|---| | Number | One metric, with the change from the period before | | Line chart, Bar chart | A metric for each day. Email apps cannot draw curves, so both arrive as bars. | | Table | The top rows of a breakdown, such as sources or campaigns | | Goals | Each goal and its conversions | | Ad spend | Spend, revenue and ROAS, then the rows you picked | | Sales, Email and texts | What your connected store or email tool reports | | Heading, Text | Your own words, with merge fields | | Highlights | The biggest changes, written for you (see below) | | Divider | A thin line | | Image or logo | Your logo, or an image at an https address | Tick **Side by side** on two blocks in a row to put them next to each other. On a phone they stack, except two numbers, which stay side by side. Conversion numbers and the Goals block are left out while the site has no goals. ### Merge fields Type these into a heading, a text block or the subject. Each one becomes its value when the email is sent. | Field | Becomes | |---|---| | `{client_name}` | The site's client name, else the site's name | | `{site_name}` | The site's name | | `{period}` | The days the report covers, like "Oct 12 to Oct 18" | | `{top_campaign}` | The best campaign (see Highlights) | | `{top_source}` | The source with the most visitors | | `{agency_name}` | Your brand name | | `{report_name}` | The report's name | | `{visitors}`, `{conversions}`, `{revenue}`, `{spend}`, `{roas}` | That total for the period | A field Sporetag does not know stays as you typed it, so a typo shows in the preview. ### Highlights The Highlights block writes 2 to 6 short lines from the numbers. It compares the period with the one before and puts the biggest changes first: ROAS, revenue, ad spend, visitors, conversions, orders, the source that moved most, and the best campaign. The best campaign is the one with the highest ROAS among campaigns with at least 5% of the spend. Without ROAS, it is the one with the most sales, then the most clicks. No AI writes these. Each line is a fixed sentence filled in with your numbers. ### Targets When the dashboard your clients see has [monthly targets](https://sporetag.com/docs/dashboards#monthly-targets), every report shows them under the summary, before its first block: each one's status, where it stands and its pace, as of the last day the report covers. There is nothing to add. ## Preview The preview on the right is the real email, drawn for the last finished period. Switch between **Desktop** and **Phone**, and **Light** and **Dark**, to see it as your client will. ## Schedule - **Every week** on a day you pick, **every month** on a day you pick, or both. Day 29 to 31 sends on the last day in shorter months. When both fall on the same day, only the monthly one goes. - **Covers**: last 7 days, last week (Monday to Sunday), last month, or month to date. Month to date sent on the 1st covers the whole month before. - **Send at**: a time on the quarter hour, in the time zone you pick. New reports start in your browser's time zone. Daylight saving moves with the clock. Every change compares with the same span just before. A whole month compares with the month before. Untick both to stop sending on a schedule. **Pause** stops it until you resume it. ## Recipients and sender - **Me**: your own address. - **Invited clients**: all the people you [invited by email](https://sporetag.com/docs/client-dashboards), only the ones you pick, or none. Someone whose access you revoke stops getting it. - **More addresses**: up to 10 more. - **Subject**: with merge fields. - **From name** and **Reply-to**: replies go to the reply-to address. New reports start with your own address there. Each email has a **View the live report** button. It opens a read-only page with the latest report. Anyone with the link can open it, and search engines are told not to list it. The link is on the report's page under **Manage**. Each email also has an unsubscribe link. It stops that report for that one address. ### Your brand With Studio, your logo is at the top when you add one in **Settings**. The email comes from Sporetag, or from "Your name via Sporetag" when you fill in a from name. With Agency, the email is white label: your logo or brand name at the top, your name as the sender, and no Sporetag name or logo. The email still comes from our sending address. ## Send now, test, PDF - **Send me a test** sends the saved report to you alone. Its subject starts with "Test:". - **Send now** sends the saved report to everyone it goes to. Click it twice to confirm. - **PDF** opens a print-ready page. Click **Save as PDF**, then pick Save as PDF in your browser's print window. Both send buttons save your changes first. You can send up to 5 reports and 10 tests an hour. ## Sent The **Sent** list shows the last sends: when, which period, and how many went out. Sporetag's email service says whether each email left, not whether it was opened, so there are no open counts. If the site's visit stats cannot be read when a report is due, Sporetag tries again every 15 minutes for 12 hours. After that it skips that send and says so in the list, rather than sending a report full of zeros. ## Your old weekly report If a site had addresses under **Weekly report** in its settings, they moved to a report named **Weekly report** on the Reports tab. It holds the same numbers and goes to the same people at the same time, Monday at 13:00 UTC. Change it like any other report. --- # Weekly reports > The Monday email report now lives on each site's Reports tab, where you can also send monthly reports, add charts and ads, and pick who gets them. Source: https://sporetag.com/docs/weekly-reports Section: Clients The weekly email report is now one of your [client reports](https://sporetag.com/docs/client-reports). Open the site, then **Reports**. Client reports are part of the Studio and Agency plans. ## What changed - If a site had addresses under **Weekly report** in its settings, they moved to a report named **Weekly report** on the Reports tab. - It holds the same numbers as before: visitors, pageviews, bounce rate, visit duration, conversions when the site has goals, top sources, top pages and goals. - It goes to the same addresses at the same time, Monday at 13:00 UTC, for the week Monday to Sunday before. Nothing more is sent than before, and nobody gets it twice. ## What you can do now - Change the day, the time and the time zone, or send it monthly too. - Add charts, ad spend, sales, your own words and highlights. - Send it to the clients you invited, not only to addresses you type. - Send a test, send it now, or save it as a PDF. The [client reports guide](https://sporetag.com/docs/client-reports) has the details. ## Stop it Open the report on the Reports tab, then **Pause**, or remove the addresses. Each email also has a link at the bottom that stops it for that one address. --- # Overview, digest and uptime > Every client site on one page, the ones that need you first, a daily or weekly digest in email, Slack or Teams, and uptime, SSL and domain checks. Source: https://sporetag.com/docs/agency-overview Section: Clients The **Overview** shows every site in your account on one page. Sites that need you come first, each with the one thing to do next. Each site is a card. Its numbers sit in a row of tiles: **Visitors, 7 days**, with the last 7 days drawn and the change against a usual week; the goal's conversions, **Ad spend** and **Tracking health** when the site has them; and **Uptime**. **Open dashboard** opens the site. ## What counts as needing attention Worst first: - **Site down.** Two uptime checks in a row failed. - **Tag stopped.** No visits in 24 hours, on a site where a usual day brings 10 or more. - **Conversions or visitors fell.** The last 7 days came in under 70% of a usual week, and well outside how much the site usually swings. A usual week is the middle of the 4 weeks before. Small sites are left out: under 70 visitors or 5 conversions a week, a drop says little. - **Ads spent with no results.** Ads spent in the last 7 days, and the site's goal got nothing. With no goal yet, it asks you to add one, unless the ad platform reports results, like signups from Meta. Those show on the row instead. - **SSL or domain ending soon.** The certificate ends within 14 days, or the domain within 30. - **An unusual change.** In the last 2 days a number moved far from a usual day for that weekday, the way that hurts: a top source or sales fell, or ad spend or cost per result rose. Muted ones are left out. See [Unusual changes](https://sporetag.com/docs/autopilot#unusual-changes). - **A sync stopped.** A connected tool, such as Shopify, stopped syncing. - **Tracking health is low.** The site's [tracking health](https://sporetag.com/docs/tracking-health) score is under 60 of 100. - **A report waits for your OK.** A report set to **Check first** is ready for you. Visits refresh every hour and goals once a day, so the page loads fast however many sites you have. Pick a client name above the list to see only that client's sites. ## What's happening on each site Under **What's happening**, each site has a short briefing for the last 7 days: a few plain sentences from its numbers, then its [weekly plan](https://sporetag.com/docs/autopilot#the-weekly-plan) and any suggested goals. **Open**, **Not now** and **Dismiss** work right there. A site's dashboard opens straight on its charts. ## The digest In **Alerts**, under **Digest and chat**, choose **Every day** or **Every Monday**, the hour and your time zone. The digest lists each site that needs you with its action, then how many are all good. It goes to your email, and to Slack or Teams when you add them. Studio and Agency include it. ### Slack 1. In Slack, add the **Incoming Webhooks** app to the channel you want. 2. Copy its webhook address. It starts with `https://hooks.slack.com/`. 3. Paste it in **Alerts**, under **Digest and chat**, and press **Save**, then **Send a test**. ### Microsoft Teams 1. In Teams, open **Workflows** and pick **Post to a channel when a webhook request is received**. 2. Choose the team and channel, then copy the address it gives you. 3. Paste it in **Alerts**, under **Digest and chat**, and press **Save**, then **Send a test**. The address lets anyone who has it post to that channel, so Sporetag stores it encrypted and shows only its last four characters. ## Uptime, SSL and domain checks On paid plans, Sporetag loads each site's home page every 15 minutes. - Each check tries three times before it counts as failed, and a site is called down only after two failed checks in a row. One slow minute never wakes anyone up. - A site is up when it answers. Server errors (500 and up), "page not found" on the home page and no answer in 15 seconds count as down. - The SSL date comes from public certificate logs, looked up once a day. Certificates usually renew a month early, so one that ends within 14 days usually means renewal is failing. - The domain date comes from the registry, looked up once a day. Some registries do not publish it; then the page says so. You get an email when a site goes down and when it is back, and when a certificate or domain is about to end. Each kind goes at most once a day per site. Tick **Also post site down, SSL and domain alerts there** to send them to Slack or Teams too. In **Alerts**, tap a site's name to see its uptime for the last 30 days. To stop these emails, turn off **Site down, SSL and domain** under **Emails**. Add the **Uptime** block to a report to show it to your client. ## The report summary Every client report opens with a short summary: **What happened**, **Why**, **What we did** and **What's next**, written from that period's numbers. - **What we did** lists changes made in Sporetag during the period, such as goals added and email flows set up. - **What's next** comes from the site's Autopilot plan. - With the Assistant on, AI writes it and uses one AI action per report period. Sporetag then checks every number in it against your data. If one does not match, the plain version written from the numbers goes instead. In the report's **Summary** card, pick **Automatic** to send it with each report, **Check first** to get an email when it is ready and send the report when you approve, or **Off**. You can change the words in either mode. --- # The partner program > For agencies on Studio and Agency. Get listed, earn up to a month of credit for each client that pays, and get help with your first three client sites. Source: https://sporetag.com/docs/partner-program Section: Clients The partner program is for agencies on Studio and Agency. It has three parts: - **A listing** on [sporetag.com/partners](https://sporetag.com/partners). - **Up to a month of credit** for each business that signs up through your link and pays for its own plan. - **Setup help** for your first three client sites, on a call with us. Credit lowers your Sporetag invoices. It is never paid out as cash. ## Apply 1. Open **Settings**, then **Partner**. 2. Fill in your agency name, city, website, the kinds of clients you serve and one short line. A logo is optional: PNG, JPEG or WebP, up to 256 KB. Without one, the listing shows your name only. 3. Tick that you agree to be listed, then click **Apply**. We check each agency by hand and email you when it is listed. Until then you can change your details on the same page. Once you are listed, write to hello@sporetag.com to change or remove the listing. ## Your referral link Once you are listed, **Settings**, **Partner** shows your link. It looks like `https://sporetag.com/r/your-agency`. When someone opens it, Sporetag keeps your code in a cookie on their browser for 90 days, then shows the sign-up page. If they create an account in that browser within the 90 days, the account counts as your referral. If they open another partner's link after yours, the last link counts. The page shows three numbers: - **Sign-ups:** accounts made through your link. - **Paying clients:** those that have paid for their own plan. - **Credit earned:** the credit already on your account, and when the next one is due. These are counts only. Sporetag never shows you who signed up. ## How credit works 1. A business signs up through your link and starts its own paid plan. A free trial does not count until its first real payment. 2. We wait 30 days from that first payment. That is the length of our money-back promise. 3. If the payment was not refunded or disputed, and the business is still on an active paid plan that is not set to end, credit goes on your account. It is one month of your own plan (the monthly price, or a twelfth of the yearly price), or what the business paid for its first paid month if that is less. A business on Solo at $29 a month earns you $29. You get an email titled "Your referral earned" and the amount. 4. Stripe takes the credit off your next invoice. Each business earns credit once, ever. If its first payment is refunded or disputed, or it stopped paying before the 30 days were up, there is no credit. You need to be on a paid Studio or Agency plan when a credit is due. If you are not, that credit lapses. ### What does not count - Your own accounts: the same account, the same Stripe customer (the billing record Stripe keeps for an account), or an email at the same domain as yours. If your address is `you@youragency.com`, a sign-up from `anyone@youragency.com` does not count. - Accounts made before someone opened your link. - Client logins you invite to a site. They are not accounts of their own. ## Setup help We set up your first three client sites with you, on a call. 1. Open **Settings**, then **Partner**, and click **Book a setup call**. 2. The form comes filled in as a partner request. Add the client's website and anything we should know. 3. We reply within one business day with a time. The page shows how many of the three are left. ## Leaving Write to hello@sporetag.com and we take the listing down. Your link stops working. Credit for clients who already paid still comes when it is due. The full rules are in the [partner terms](https://sporetag.com/terms#partners), which are a draft until the legal entity behind Sporetag is named. --- # Data and privacy > What Sporetag records about your visitors, what it never stores, where the data lives, how long it is kept, and how to export or delete it. Source: https://sporetag.com/docs/data-and-privacy Section: Account This page is about the visitors to the sites you track. For what we do with your own account data, read the [privacy policy](https://sporetag.com/privacy). ## What is recorded for each event - The page path and the referrer's host name. - UTM tags, and ad click ids if the landing address had them. - Country, device type, browser and operating system. These are worked out from the request and the IP address is then dropped. - How long the page was visible. - A visitor hash, so one person counts once. - For a click: the short link it was. ## What is never stored - The IP address. - The full user agent string. - Cookies or anything in the browser, in Private mode. - Plain emails and phone numbers in your stats. Emails and phones you send are kept only as a SHA-256 hash, except that [customer profiles](https://sporetag.com/docs/customer-profiles) keep the email, name and phone number (and details from an import) encrypted while **Show contact details** is on. ## The visitor hash In Private mode a visitor is `sha256(salt, site, IP, user agent)`. The salt changes every day and the old one is deleted. So nobody, us included, can link a visitor across days or across sites. In [90-day tracking](https://sporetag.com/docs/tracking-modes) the script also keeps a random first-party id on your domain for 90 days. It is not linked to any other site. ## Visitor profiles With 90-day tracking, after consent when you wait for it, each first-party id gets an anonymous [visitor profile](https://sporetag.com/docs/customer-profiles#visitors-before-they-give-an-email) in D1. It keeps the random id, first and last seen, the number of visits, the landing page, the first and latest source and ad platform, countries, devices and the browser. It keeps no IP address, email, phone or name. It is deleted 90 days after the last visit. Its page reads the visits themselves from the event store. In Private mode no profile is made. ## Where it lives Sporetag runs on Cloudflare. Events are stored in Cloudflare Workers Analytics Engine. Accounts, sites, links and goals are stored in Cloudflare D1. We do not offer EU-only hosting today. ## How long it is kept Your plan sets how far back you can see: 30 days on Free and 2 years on Solo, Studio and Agency. See [Billing and limits](https://sporetag.com/docs/billing-and-limits). ## Export Every list in the dashboard has a CSV export. ## Delete Delete one customer or visitor, or forget an email for a data request, on the site's **Profiles** tab. A deleted visitor's device id is never given a profile again on that site. See [Profiles](https://sporetag.com/docs/customer-profiles#privacy). Delete a site in its settings to remove it from your account. To close your account and remove your data, email hello@sporetag.com from the address on the account. ## Sending data to Meta Nothing goes to Meta unless you connect a site to the [Meta Conversions API](https://sporetag.com/docs/meta-conversions-api) and mark goals to send. Then only those goals' conversions are sent, with hashed contact details. The same holds for the platforms under [Send results to your ad accounts](https://sporetag.com/docs/send-results-to-ad-accounts). What went to Google Ads or Microsoft Ads for a sale (the click id and hashed contact details) is kept encrypted for 30 days, so a refund can change that sale. It is deleted after that, or as soon as you turn off **Refunds** or the platform. ## Global Privacy Control A visitor whose browser sends [Global Privacy Control](https://globalprivacycontrol.org/) (`Sec-GPC: 1`) is never sent to Meta or any other ad platform. With 90-day tracking, the signal is kept with their random id for 13 months, and later sales or deals tied to it are not sent either. First-party statistics are not a sale or a share, so the visit is still counted. --- # Billing and limits > What each Sporetag plan includes, what counts toward your monthly allowance, how overage works, and how to read, change or cancel your plan in Billing. Source: https://sporetag.com/docs/billing-and-limits Section: Account Prices on this page are drafts and may change before launch. The [pricing page](https://sporetag.com/pricing) always has the current numbers. ## What each plan includes | | Free | Solo | Studio | Agency | Custom | |---|---|---|---|---|---| | Price | $0 | $29 a month or $290 a year | $79 a month or $790 a year | $199 a month or $1,990 a year | [Talk to us](https://sporetag.com/setup-call?plan=custom) | | Sites | 1 | 5 | 25 | 100 | Unlimited | | Pageviews and clicks a month | 5,000 | 100,000 | 1,000,000 | 5,000,000 | Unlimited | | Active short links | 5 | 250 | Unlimited | Unlimited | Unlimited | | Custom short domains | None | 1 | 5 | 20 | Unlimited | | History | 30 days | 2 years | 2 years | 2 years | Unlimited | | Goals per site | 2 | Unlimited | Unlimited | Unlimited | Unlimited | | Events API and script proxy | No | Yes | Yes | Yes | Yes | | 90-day tracking and attribution report | No | Yes | Yes | Yes | Yes | | Meta Conversions API | No | Yes | Yes | Yes | Yes | | Custom link endings | No | Yes | Yes | Yes | Yes | | Client dashboards | No | No | Yes | Yes | Yes | | Weekly reports | No | No | Yes | Yes | Yes | | Your logo | No | No | Yes | Yes | Yes | | White label | No | No | No | Yes | Yes | Free is a small way to try the basic stats. It has no Events API, script proxy, attribution or Meta Conversions API. Those are on Solo, Studio, Agency and Custom. Agency adds white label. Client dashboards and weekly reports then show only your name and logo, with no Sporetag branding. ## What counts One allowance covers a calendar month (UTC): - Pageviews. - Clicks on your short links. Custom events, Events API events and automatic events do not count. Bots that we filter out do not count either. The month starts again on the 1st. ## Going over There is no hard stop. Your stats keep coming in. - **First month over:** we tell you, and that is all. You are not charged. - **Second month over in a row:** extra use is billed in blocks of 500,000 events for $10 each. So one busy month never brings a surprise bill. If you are over two months running, it is usually cheaper to move up a plan, and we will say so. ## Your Billing page Open **Settings**, then **Billing**. **Your plan** is at the top. It shows: - **Price**: what you pay, a month or a year. - **Next payment**: the date Stripe charges your card next. - **Trial** and **First payment**, while a trial runs: the days left and the date of the first charge. - **Ends**, after you cancel: the last day of the plan. **Card and invoices** opens Stripe, where you update your card and download invoices. **Change plan** jumps to the plans. **Cancel plan** starts the cancel flow. **This month** has a meter for each limit: pageviews and clicks, active short links, live sites and AI actions. A meter turns amber at 80%. Counts update about every 15 minutes, and the date they reset is in the corner. Anything with no limit on your plan is named once, under the title. When you go past your plan, one **Past your plan** line says what, how much, and whether it is billed yet. On paid plans, **Usage limit** caps what AI actions, texts and emails past your plan can cost in a month. Open it to change the amount. **Plans** marks the one you are on with **Current plan**. The other buttons say what happens: **Upgrade to Studio**, **Downgrade to Solo**. Pick **Yearly** above the plans to see **Switch to yearly** on your own plan. On a phone each plan shows its price and limits; **Compare every feature** opens the full table. ## Usage Call tracking and texts are priced by use, on top of your plan. Billed with your plan each month: | Usage | Price | |---|---| | Call tracking number, local or toll-free | $3 a month | | Calls, recording included | 5¢ a minute | | Texting setup, once | $25 | | Texting number | $5 a month | | Texts | 2¢ a part; long texts count as 2 or more | Calls and texts are (when shipped). What you used shows under **Past your plan** in Billing. ## Paying Plans are paid by card through Stripe, monthly or yearly. Yearly costs the same as 10 months. We never see or store your card number. Bigger agencies can ask for the Custom plan. It has no limits, and we set the price with you. Use **Talk to us** on the [pricing page](https://sporetag.com/pricing), or [book a call](https://sporetag.com/setup-call?plan=custom). We bill it by card through Stripe or by invoice. ## 14-day free trial Your first paid plan is free for 14 days. Checkout asks for your card, and Stripe charges nothing until day 15. **Billing** shows the day your trial ends. To stop, cancel in **Billing** before the trial ends. You pay nothing, and when the trial ends your account moves to Free. The trial is for an account's first paid plan only. Free needs no card at all. ## If a payment fails Nothing stops at once. You have 7 days from the failed payment to fix it, and your plan keeps working the whole time. A red bar at the top of the app says the date. **Retry payment** opens a window with your saved card and what is due today: - **Retry now** charges the saved card right away. When it goes through, the bar is gone. - **Change** lets you use another card, then retry. - If the card is refused, the window says why in plain words, such as "Card expired". - If your bank wants to confirm the payment, **Confirm with your bank** opens Stripe's page to finish it. After 7 days without payment, your account works like Free. Nothing is deleted, and your tracking keeps counting. Sites and links past Free's room are read-only. Pay the bill and your plan is back at once. ## 30-day money back If Sporetag is not right for you, ask within 30 days of your first payment and we refund that payment in full. After a free trial, the 30 days start with the first payment. No questions asked. Write to hello@sporetag.com from your account email. We end the plan at the same time, and your account moves to Free. Stripe returns the money to your card, usually within 5 to 10 days. Later renewals are not refunded, so cancel before the next one if you are done. The full wording is in the [terms](https://sporetag.com/terms#refunds). ## Change or cancel - **Upgrade** or **Downgrade** between paid plans starts at once. Stripe puts the difference, a charge or a credit, on your next invoice. - **Cancel plan** asks why, then offers what fits, such as a pause. A canceled plan stays on until the end of the time you paid for, then the account moves to Free. Your data stays, within the Free plan's 30 days of history. ## Questions Email hello@sporetag.com. --- # Read API > Read stats, goals, attribution, ad spend and short links with a read key. JSON over HTTPS, OpenAPI 3.1, CSV feeds and copyable curl examples. Source: https://sporetag.com/docs/api Section: Developers The read API gives your own code, a client's dashboard or a spreadsheet the same numbers you see in Sporetag. It only reads. Nothing it does can change a site, a goal or a link. The read API is on paid plans: Solo, Studio, Agency and Custom. It also powers the [MCP server](https://sporetag.com/docs/mcp) and [Google Sheets feeds](https://sporetag.com/docs/looker-studio). ## Make a key 1. Open **Settings**, then **API**. 2. Name the key, pick what it reads (**All sites**, or one site) and press **Make a key**. 3. Copy the key. It is shown once. Sporetag keeps only a hash of it. A key starts with `st_rk_`. **All sites** covers sites you add later too. For a client, a script that runs somewhere else, or a shared sheet, make a key for one site. **Revoke** stops a key at once. Read keys are not [Events API](https://sporetag.com/docs/events-api) keys. Events API keys (`st_sk_`) send events and cannot read. Read keys (`st_rk_`) read and cannot send. ## First request ```bash export SPORETAG_KEY="st_rk_..." curl https://sporetag.com/api/v1/sites \ -H "Authorization: Bearer $SPORETAG_KEY" ``` ```json { "data": [ { "id": "8fK2pQ", "name": "Demo shop", "domain": "shop.example.com", "client_label": null, "timezone": "America/New_York", "tracking_mode": "attribution", "created_at": "2026-09-14T16:02:11.000Z" } ], "pagination": { "page": 1, "limit": 100, "has_more": false, "next_page": null } } ``` Every other call takes a site `id` from this list. ## Endpoints All are `GET` under `https://sporetag.com`. The full schema is the [OpenAPI 3.1 document](https://sporetag.com/api/v1/openapi.json). | Endpoint | What it returns | |---|---| | `/api/v1/sites` | Sites the key reads | | `/api/v1/sites/{site_id}` | One site | | `/api/v1/sites/{site_id}/stats` | Totals for a range, the span before it, and the change | | `/api/v1/sites/{site_id}/timeseries` | The same totals per hour, day or month | | `/api/v1/sites/{site_id}/breakdown/{dimension}` | Top sources, pages, campaigns, countries, devices or goals | | `/api/v1/sites/{site_id}/goals` | Goals with conversions | | `/api/v1/sites/{site_id}/attribution` | Conversions and revenue credited by source, campaign, ad, platform or short link | | `/api/v1/sites/{site_id}/ads` | Ad spend, credited revenue and ROAS | | `/api/v1/links` | Short links with clicks | | `/api/v1/links/{link_id}` | One link: clicks per day and where they came from | ### Totals ```bash curl "https://sporetag.com/api/v1/sites/8fK2pQ/stats?period=7d" \ -H "Authorization: Bearer $SPORETAG_KEY" ``` ```json { "data": { "site_id": "8fK2pQ", "range": { "period": "7d", "date_from": "2026-10-17", "date_to": "2026-10-23", "timezone": "America/New_York", "from": "2026-10-17T00:00:00-04:00", "to": "2026-10-23T11:00:00-04:00" }, "previous_range": { "compare": "previous", "match_weekdays": false, "from": "2026-10-10T00:00:00-04:00", "to": "2026-10-16T11:00:00-04:00" }, "filters": {}, "metrics": { "visitors": 1840, "visits": 2210, "pageviews": 5120, "views_per_visit": 2.32, "bounce_rate": 41, "visit_duration": 96, "conversions": 63, "conversion_rate": 2.9 }, "previous": { "visitors": 1702, "visits": 2050, "pageviews": 4790, "views_per_visit": 2.34, "bounce_rate": 43, "visit_duration": 91, "conversions": 55, "conversion_rate": 2.7 }, "change_pct": { "visitors": 8.1, "visits": 7.8, "pageviews": 6.9, "views_per_visit": -0.9, "bounce_rate": -4.7, "visit_duration": 5.5, "conversions": 14.5, "conversion_rate": 7.4 } } } ``` The numbers above are an example. `bounce_rate` and `conversion_rate` are percents. `visit_duration` is seconds per visit. `conversions` counts visits that reached any goal. `previous_range` is the span the change is measured against. By default it is the same number of days just before, ending at the same time of day, so a part day is compared with a part day. This month, quarter or year compares with the same days of the one before: October 1 to 23 against September 1 to 23. Add `compare=year` for the same dates a year back, and `match_weekdays=true` with it to go back 364 days so a Monday lines up with a Monday. Add `compare=false` to skip it. ### Per day ```bash curl "https://sporetag.com/api/v1/sites/8fK2pQ/timeseries?period=30d&interval=day" \ -H "Authorization: Bearer $SPORETAG_KEY" ``` `interval` is `day` (the default), `hour` (up to 7 days) or `month`. Every bucket is in the list, empty ones too. `date` is the local day (`2026-10-01`), hour (`2026-10-01 14:00`) or month (`2026-10`). ### Breakdowns ```bash curl "https://sporetag.com/api/v1/sites/8fK2pQ/breakdown/source?period=30d&limit=10" \ -H "Authorization: Bearer $SPORETAG_KEY" ``` Dimensions: `source`, `referrer`, `utm_source`, `utm_medium`, `utm_campaign` (or `campaign`), `utm_content`, `utm_term`, `page`, `entry_page`, `country`, `device`, `browser`, `os` and `goal`. Rows come most visitors first, each with visitors, visits, pageviews, bounce rate, visit duration, conversions and conversion rate. A blank source is `Direct / None`. ### Goals ```bash curl "https://sporetag.com/api/v1/sites/8fK2pQ/goals?period=mtd" \ -H "Authorization: Bearer $SPORETAG_KEY" ``` Each goal has `conversions` (visits that reached it), `events` (every match) and `conversion_rate` (percent of visits). ### Attribution ```bash curl "https://sporetag.com/api/v1/sites/8fK2pQ/attribution?period=30d&by=campaign&model=last" \ -H "Authorization: Bearer $SPORETAG_KEY" ``` This is the [attribution report](https://sporetag.com/docs/attribution-report). `by` is `source`, `campaign`, `content` (the ad), `term` (the ad set or keyword), `platform` or `link`. `model` is `last` (the default) or `first`. `goal_id` counts one goal. Revenue is per currency, such as `{"USD": 1240.5}`, and never converted. ### Ad spend and ROAS ```bash curl "https://sporetag.com/api/v1/sites/8fK2pQ/ads?period=30d&level=campaign" \ -H "Authorization: Bearer $SPORETAG_KEY" ``` From connected ad platforms and [spend files](https://sporetag.com/docs/csv-spend-import). `level` is `platform`, `campaign`, `adset` or `ad`. `revenue` is what Sporetag credits to the ads, last touch. `platform_reported` is what the platform itself counts. `roas` is null when there is no spend or when spend and revenue are in different currencies. `connected` is `false` when the site has no ad spend. ### Short links ```bash curl "https://sporetag.com/api/v1/links?period=30d" \ -H "Authorization: Bearer $SPORETAG_KEY" curl "https://sporetag.com/api/v1/links/LINK_ID?period=30d" \ -H "Authorization: Bearer $SPORETAG_KEY" ``` A key for one site lists the links tied to that site. Add `site_id` to an all-sites key to do the same. `status` is `active` (the default), `archived` or `all`. ## Dates and time zones Send a `period`, or `date_from` and `date_to` as `YYYY-MM-DD`. Both days are included. | `period` | Covers | |---|---| | `today` | Today, up to now | | `yesterday` | Yesterday | | `7d`, `30d`, `90d` | The last 7, 30 or 90 days, today included (default `30d`) | | `12m` | The last 365 days | | `mtd` | This month, up to now | | `lastmonth` | Last calendar month | | `quarter` | This quarter, up to now | | `lastquarter` | Last calendar quarter | | `year` | This year, up to now | Days start at local midnight in one time zone: the `timezone` you send (an IANA name such as `Europe/Berlin`), else the site's, else UTC. Every answer repeats the range with ISO 8601 times and their offset, so you never have to guess. Days and months in a time series use the zone's offset at the start of the range. Short link clicks are kept in whole UTC days, so link calls are always UTC. A range can be up to 731 days, and only as far back as your plan keeps stats. ## Filters Add `filter=dimension:value`. Repeat it to combine, up to 8. ```bash curl -G "https://sporetag.com/api/v1/sites/8fK2pQ/stats" \ --data-urlencode "period=30d" \ --data-urlencode "filter=source:Instagram" \ --data-urlencode "filter=device:Mobile" \ -H "Authorization: Bearer $SPORETAG_KEY" ``` Filters work on stats, time series, breakdowns and goals. A `goal` filter takes a goal id from the goals call. ## Pages of results Lists take `limit` (1 to 1,000, default 100) and `page` (from 1). The answer says if there is more: ```json "pagination": { "page": 1, "limit": 100, "has_more": true, "next_page": 2 } ``` Lists go 1,000 rows deep. ## CSV feeds Add `format=csv` to any list for a CSV file with every row. For tools that cannot send headers, such as Google Sheets, the key can ride in the address, for CSV feeds only: ```text https://sporetag.com/api/v1/sites/8fK2pQ/timeseries?period=90d&format=csv&key=st_rk_... ``` Anyone with that address can read what the key reads. Use a key for one site, and revoke it if the address leaks. See [Google Sheets and Looker Studio](https://sporetag.com/docs/looker-studio). ## Errors Errors have a status code and the same shape: ```json { "error": { "code": "invalid_parameter", "message": "date_from must be a date as YYYY-MM-DD.", "field": "date_from" } } ``` | Status | Code | Means | |---|---|---| | 400 | `invalid_parameter`, `range_too_long`, `key_in_url` | A parameter is wrong. `field` names it | | 401 | `unauthorized` | No key, or the key was revoked | | 403 | `plan` | The account's plan does not include the read API | | 403 | `history_limit` | The range starts before the plan keeps stats | | 404 | `not_found` | No such site, link or endpoint for this key | | 429 | `rate_limited` | Over the rate limit. Wait `Retry-After` seconds | | 502, 503 | `upstream_error`, `stats_unavailable` | Stats could not be read. Try again in a minute | A site or link another key or account owns reads as `not_found`, never as forbidden. ## Rate limit Each key can make 120 requests a minute, across the read API, CSV feeds and the MCP server. Every answer has `X-RateLimit-Limit` and `X-RateLimit-Remaining`. ## Safety - Keep keys on a server or in a password manager. The API sends no CORS headers, so a web page cannot call it. - Each key reads only its sites. Revoke it in **Settings**, **API** and it stops at once. - Answers never include visitor emails, names or phone numbers. --- # MCP server for Claude and ChatGPT > Connect Claude, ChatGPT or another AI assistant to Sporetag with a read key, then ask how your site did last week in plain words. Source: https://sporetag.com/docs/mcp Section: Developers Sporetag has a remote MCP server. MCP (Model Context Protocol) is the open standard AI assistants use to read other tools. Once it is connected, ask your assistant things like: - "How did shop.example.com do last week compared with the week before?" - "Which campaigns brought sales this month?" - "What is my ROAS on Meta for the last 30 days?" - "Which short link got the most clicks this week?" The assistant reads the numbers through Sporetag and answers from them. It can only read. It cannot change a site, a goal, a link or a setting. The MCP server is on paid plans: Solo, Studio, Agency and Custom. [Sporetag for AI assistants](https://sporetag.com/ai) has the short version, more questions to ask, and where AI tools find Sporetag's docs as Markdown. ## 1. Make a read key Open **Settings**, then **API**, and make a key. Pick **All sites**, or one site if the assistant should only see that one. Copy the key. It is shown once. See [Read API](https://sporetag.com/docs/api) for more on keys. ## 2. Connect your assistant The server lives at: ```text https://sporetag.com/mcp ``` It takes the key as `Authorization: Bearer st_rk_...`. Apps that only take an address can use the key in the address instead: ```text https://sporetag.com/mcp/st_rk_... ``` Treat that address like a password. Anyone who has it can read what the key reads. ### Claude (claude.ai and the desktop app) 1. Open **Settings**, then **Connectors**. 2. Choose **Add custom connector**. 3. Name it **Sporetag**. For the URL, paste the address with your key: `https://sporetag.com/mcp/st_rk_...` 4. Leave the OAuth fields empty and press **Add**. 5. In a chat, turn on Sporetag from the tools menu, then ask a question. On Team and Enterprise plans, an owner may need to add the connector for the organization first. ### Claude Code ```bash claude mcp add --transport http sporetag https://sporetag.com/mcp \ --header "Authorization: Bearer st_rk_..." ``` ### ChatGPT Custom MCP servers in ChatGPT need developer mode, which OpenAI offers on some plans. Turn it on under **Settings**, **Apps and Connectors**, **Advanced**. Then create a connector with the address that has your key in it, and choose no authentication. OpenAI may name these menus differently on your plan. ### Cursor, VS Code and other MCP clients Most clients take a JSON entry like this: ```json { "mcpServers": { "sporetag": { "url": "https://sporetag.com/mcp", "headers": { "Authorization": "Bearer st_rk_..." } } } } ``` A client that only runs local servers can reach it through `mcp-remote`: ```json { "mcpServers": { "sporetag": { "command": "npx", "args": ["mcp-remote", "https://sporetag.com/mcp", "--header", "Authorization: Bearer st_rk_..."] } } } ``` ## Tools | Tool | What it reads | |---|---| | `list_sites` | Your sites: id, name, address and time zone | | `get_stats` | Visitors, visits, pageviews, bounce rate, visit duration, conversions and conversion rate, with the span before; optionally per hour, day or month | | `get_breakdown` | Top sources, referrers, UTM values, pages, countries, devices, browsers or goals | | `get_goals` | Goals with conversions and conversion rate | | `get_attribution` | Conversions and revenue credited by source, campaign, ad, ad set, platform or short link, first or last touch | | `get_ad_spend` | Ad spend, credited revenue and ROAS by platform, campaign, ad set or ad | | `get_links` | Short links with clicks | Every tool is marked read-only. Dates work as in the [read API](https://sporetag.com/docs/api#dates-and-time-zones): whole local days in the site's time zone, unless the assistant passes another. ## Good to know - Each request counts toward the key's 120 requests a minute, shared with the read API. - Source names, page paths and campaign names come from visitors and ad platforms. The server tells the assistant to treat them as data, never as instructions. - No visitor emails, names or phone numbers are ever sent to the assistant. - To disconnect, remove the connector in your assistant and revoke the key in **Settings**, **API**. ## Docs your assistant can read Sporetag's docs come as plain Markdown too, so an assistant can read them without a browser: - [/llms.txt](https://sporetag.com/llms.txt): a short map of the site, linking to the Markdown copies. - [/llms-full.txt](https://sporetag.com/llms-full.txt): every docs article, guide, platform page and glossary term in one file. - Any docs, guide or glossary page with `.md` on the end, such as [/docs/mcp.md](https://sporetag.com/docs/mcp.md). A request that asks for `text/markdown` in its `Accept` header gets the same. ## For developers The server speaks MCP over Streamable HTTP: JSON-RPC 2.0 in a `POST`, one JSON answer back, no server-sent events and no session. It supports protocol versions 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05, and the methods `initialize`, `ping`, `tools/list` and `tools/call`. `GET` answers 405. ```bash curl https://sporetag.com/mcp \ -H "Authorization: Bearer $SPORETAG_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_stats","arguments":{"site_id":"8fK2pQ","period":"7d"}}}' ``` --- # Google Sheets and Looker Studio > Put Sporetag numbers in Google Sheets with one formula that refreshes by itself, then chart them in Looker Studio. Source: https://sporetag.com/docs/looker-studio Section: Developers Every list in the [read API](https://sporetag.com/docs/api) has a CSV feed. Google Sheets reads a feed with one formula and refreshes it by itself, and Looker Studio charts any sheet. That is the path today. A Sporetag connector for Looker Studio (when shipped) will let you pick a site and a report inside Looker Studio, with no sheet in between. CSV feeds are on paid plans: Solo, Studio, Agency and Custom. ## 1. Make a key for one site Open **Settings**, then **API**. Under **Reads**, pick the site, name the key (for example "Sheets") and press **Make a key**. Copy it. A feed address holds the key, and Google fetches it from its own servers. Anyone who sees the formula can read that site. A key for one site keeps that small, and **Revoke** stops it at once. ## 2. Find the site id The site's dashboard address ends with it: `sporetag.com/app/s/8fK2pQ` has the id `8fK2pQ`. ## 3. Add a feed to Google Sheets In an empty sheet, click cell A1 and paste a formula. Put your site id and key in. Visitors per day for the last 90 days: ```text =IMPORTDATA("https://sporetag.com/api/v1/sites/8fK2pQ/timeseries?period=90d&format=csv&key=st_rk_...") ``` Top sources this month: ```text =IMPORTDATA("https://sporetag.com/api/v1/sites/8fK2pQ/breakdown/source?period=mtd&format=csv&key=st_rk_...") ``` More feeds, all with `&format=csv&key=st_rk_...` at the end: | Feed | Address after `https://sporetag.com` | |---|---| | Totals for a range, one row | `/api/v1/sites/SITE_ID/stats?period=30d` | | Per day, hour or month | `/api/v1/sites/SITE_ID/timeseries?period=90d&interval=day` | | Top pages | `/api/v1/sites/SITE_ID/breakdown/page?period=30d` | | Campaigns | `/api/v1/sites/SITE_ID/breakdown/campaign?period=30d` | | Countries or devices | `/api/v1/sites/SITE_ID/breakdown/country?period=30d` | | Goals | `/api/v1/sites/SITE_ID/goals?period=30d` | | Sales credited by campaign | `/api/v1/sites/SITE_ID/attribution?period=30d&by=campaign` | | Ad spend and ROAS by campaign | `/api/v1/sites/SITE_ID/ads?period=30d&level=campaign` | | Short link clicks | `/api/v1/links?period=30d` | Money feeds have one currency column. Add `¤cy=EUR` to pick it; by default it is the one with the most money. Google Sheets refreshes these formulas on its own, about once an hour. Put each feed on its own tab, so they never overlap. ## 4. Chart it in Looker Studio 1. In [Looker Studio](https://lookerstudio.google.com), create a report and choose **Add data**. 2. Pick **Google Sheets**, then your sheet and the tab with the feed. 3. Keep **Use first row as headers** on and press **Add**. 4. Check that `date` reads as a date: in the data source, set its type to **Date** if Looker Studio did not. Charts update when the sheet does. ## Good to know - Feed numbers are the same as the dashboard's: whole days in the site's time zone. Add `&timezone=America/New_York` to read them in another. - A feed holds up to 1,000 rows. - Each refresh counts toward the key's 120 requests a minute. - If a feed stops, the cell shows an error. A revoked key or a plan change is the usual reason. --- # Why your analytics numbers never match > GA4, Shopify, Meta and Google Ads count with different rules, dates and blind spots. Where each number splits, and which one to trust for each question. Source: https://sporetag.com/guides/why-analytics-numbers-dont-match By the Sporetag team. Updated October 23, 2026. Open Meta Ads Manager, Google Ads, GA4 and your store on the same morning and you will get four different answers to "how many sales did we make yesterday?" None of them is broken. Each one counts something slightly different, credits it by a different rule, and puts it on a different day. Once you know the five places the numbers split, most gaps stop being a mystery. Some can be closed. The rest just need to be read the right way. ## The five reasons numbers differ 1. **They count different things.** An ad platform counts clicks and the conversions it can tie to people who saw or clicked an ad. An analytics tool counts sessions or visits. A store counts orders. A click is not a visit, and a visit is not a buyer. 2. **They credit different touches.** Most buyers touch more than one channel. Each tool has an [attribution](https://sporetag.com/glossary/attribution) rule for who gets the sale, and the rules disagree on purpose. 3. **They look back over different windows.** Meta counts a purchase within 7 days of a click by default. Google Ads uses a 30-day window unless you change it. GA4 looks back 90 days for most [key events](https://sporetag.com/glossary/key-event). 4. **They put the sale on different dates.** Google Ads reports a conversion on the day of the ad click, not the day of the purchase. Your store reports it on the day the order was paid. Time zones move the line again. 5. **They see different slices of traffic.** Ad blockers, consent banners, Safari's storage limits, checkout pages that do not run your tags, and bots all change what each tool can see. ## Different things being counted Clicks in an ad platform are almost always higher than visits in analytics. Between a click and a counted visit, people close the tab before the page loads, the tag is blocked, the click came from a bot the ad network did not filter, or someone clicked twice. A gap here is normal. A gap that suddenly widens is worth checking, because it often means the tag stopped loading on a landing page. Visits, sessions and users are also defined differently from tool to tool. GA4 starts a new session after 30 minutes of inactivity by default. Sporetag counts a visit as one visitor's day on a site. Shopify has its own session rules. The guide to [visitors, sessions and pageviews](https://sporetag.com/guides/sessions-users-pageviews) covers each definition, and the same gap shows as a step on the day you move from GA4 to another tool (see [leaving GA4 without losing your history](https://sporetag.com/guides/import-ga4-history)). ## Different credit rules Take one buyer who taps a Meta ad on their phone on Monday, searches your brand name on a laptop on Thursday, clicks the Google ad at the top, and buys. - **Meta** counts the purchase if it can match the buyer to the person who tapped the ad, inside its attribution setting. Its default for website conversions is 7-day click and 1-day view, and since early 2026 it also has a separate 1-day "engage-through" window for non-link clicks ([Jon Loomer, March 2026](https://www.jonloomer.com/meta-ads-attribution-2026/)). - **Google Ads** counts the conversion too, because the buyer clicked a Google ad inside its window. - **GA4** gives the credit to one channel or splits it with its data-driven model. All of GA4's models leave direct visits out of the credit unless the whole path was direct ([Google](https://support.google.com/analytics/answer/10596866)). - **Shopify** uses "last non-direct click" by default ([Shopify](https://www.shopify.com/blog/marketing-insights)), so it credits the Google search. The two ad platforms both claim the sale. Add up "conversions" across ad platforms and you will almost always get more sales than you made. That is not fraud. Each platform answers "did my ad play a part?", and both did. The [attribution models guide](https://sporetag.com/guides/attribution-models-explained) works through the same path under each rule. ## Different windows and dates | Tool | Default window | Date a sale lands on | |---|---|---| | Meta Ads Manager | 7-day click, 1-day view, 1-day engage-through | Changed in 2025: website conversions moved to the conversion date ([Supermetrics](https://docs.supermetrics.com/docs/facebook-ads-reach-and-attribution-changes-june-10-2025)) | | Google Ads | 30 days for Search and Display, 1 to 90 allowed ([Google](https://support.google.com/google-ads/answer/3123169)) | The ad click's date, unless you use the "by conv. time" columns ([Google](https://support.google.com/google-ads/answer/9549009)) | | GA4 | 90 days for most key events, 30 for first visits ([Google](https://support.google.com/analytics/answer/10597962)) | The event's date | | Shopify | Last non-direct click | The order's date | | Klaviyo | 5 days after an email open or click, last touch ([Klaviyo](https://help.klaviyo.com/hc/en-us/articles/115005248128)) | The send date. See [Klaviyo attribution](https://sporetag.com/guides/klaviyo-attribution) | The click-date rule matters most for short reporting periods. If someone clicks on the 30th and buys on the 2nd, Google Ads puts the sale in last month and your store puts it in this month. Over a quarter it evens out. Over a week it can swing a report. Check the time zone setting in every tool too. An ad account set to Pacific time and a store set to Eastern time draw "yesterday" three hours apart. ## Different blind spots - **Ad blockers and privacy browsers** stop many third-party tags from loading. Tags served from big ad and analytics domains are the most commonly blocked. - **Consent banners.** Where a visitor declines, a well-built site does not set analytics cookies or fire ad pixels for them. If your banner blocks GA4 until consent, GA4 never sees those visits, while your store still records the order. - **Safari limits.** Safari caps cookies set by script at 7 days ([WebKit](https://webkit.org/blog/8613/intelligent-tracking-prevention-2-1/)). A buyer who clicks an ad and comes back on day 9 can look like a new visitor. Safari also strips known click ids from links opened from Mail, Messages and Private Browsing ([Apple](https://www.apple.com/newsroom/2023/06/apple-announces-powerful-new-privacy-and-security-features/)). - **Checkout pages.** Shopify's checkout does not run your theme code, and script tags on Shopify's order status page stopped running for all stores in August 2026 ([Shopify](https://shopify.dev/docs/apps/build/online-store/script-tag-deprecation/order-status)). A tag that only lives in the theme cannot see the purchase. - **Bots.** Some tools filter more bots than others. A tool that counts a scraper as a visitor will show more visits and a lower conversion rate. ## Gaps that are bugs, not rules Some differences are mistakes you can fix: - **The tag is missing from some pages.** A landing page built in a separate tool often has no analytics tag at all. - **The tag is on the page twice.** Two copies double pageviews and conversions, and push the bounce rate toward zero. The free [tag checker](https://sporetag.com/tools/tag-checker) lists every analytics and ad tag a page loads. - **Payment pages show up as referrals.** If buyers leave for PayPal or a payment processor and come back, GA4 can credit the sale to that referral. Add those domains to GA4's list of unwanted referrals. - **UTM tags on your own links.** A tagged link from your home page to your shop overwrites the real source of the visit. Use UTM tags only on links that point to your site from somewhere else. - **The purchase event fires on page reload.** A thank-you page that sends "purchase" every time it loads counts the same order again each time the buyer comes back to it. ## Which number to trust for which question | Question | Trust this | Why | |---|---|---| | How much did we sell? | Your store or payment processor | It counts paid orders, once, with refunds | | Which channels bring buyers? | One analytics tool, with one consistent rule | Same rule across every channel, so the comparison is fair | | Is this campaign improving? | The ad platform's own number, as a trend | It is the number the platform optimizes on | | Should we move budget between platforms? | Your store's revenue against each platform's spend | The platforms' own claims overlap | The mistake is mixing them: dividing Meta's claimed revenue by Meta's spend, then adding Google's claimed revenue on top, and calling the total "return on ad spend". Use the store's revenue for any number you add up. See [ROAS, blended ROAS and MER](https://sporetag.com/guides/roas-mer-blended-roas). ## How to make the numbers agree more closely 1. Set the same time zone and currency in every tool. 2. Tag every link you control with [UTM parameters](https://sporetag.com/guides/utm-parameters), with one naming scheme. Mediums GA4 does not know end up in [Unassigned](https://sporetag.com/guides/ga4-unassigned-traffic). 3. Put your analytics tag on every page, once, including landing pages built in other tools. 4. Send paid orders from your server or your store's own data, not only from a thank-you page script. The [server-side tracking guide](https://sporetag.com/guides/server-side-vs-client-side-tracking) explains how. 5. For ad platforms, send conversions back through their server APIs with an event id, so the browser and server copies count once ([Meta](https://developers.facebook.com/docs/marketing-api/conversions-api/deduplicate-pixel-and-server-events)). 6. Compare the same date range on the same date basis. In Google Ads, add the "by conv. time" columns when you compare with your store. ## Common questions ### What is a normal gap between GA4 and Shopify? There is no single normal figure, because it depends on how many of your visitors block tags, decline consent or use Safari. Measure your own gap over a full month, then watch it. A steady gap is fine to live with. A sudden change usually means a tag broke. ### Why does Meta report more purchases than my store? Meta counts purchases from people who clicked or saw an ad inside its window, including some it matches across devices, and other platforms count the same purchases too. Your store counts each order once. Meta also reports by its own dates and can include modeled conversions. ### Should I trust the ad platform or my analytics? Use the store for how much you sold, one analytics tool for comparing channels, and each ad platform for trends inside that platform. Do not add the platforms' claimed sales together. ### Do server-side tracking tools make the numbers match? They close part of the gap by seeing sales a browser tag missed, and by sending them back with ids that prevent double counts. They do not remove different credit rules, windows or dates, so the tools will still disagree. ## Sources - Google Analytics: [Get started with attribution](https://support.google.com/analytics/answer/10596866), [Select attribution settings](https://support.google.com/analytics/answer/10597962). Checked October 2026. - Google Ads: [About conversion windows](https://support.google.com/google-ads/answer/3123169), [Conversions by time](https://support.google.com/google-ads/answer/9549009). Checked October 2026. - Shopify: [Marketing insights](https://www.shopify.com/blog/marketing-insights), [Order status script tags](https://shopify.dev/docs/apps/build/online-store/script-tag-deprecation/order-status). Checked October 2026. - Meta: [Deduplicate pixel and server events](https://developers.facebook.com/docs/marketing-api/conversions-api/deduplicate-pixel-and-server-events). Attribution settings as described by [Jon Loomer](https://www.jonloomer.com/meta-ads-attribution-2026/) and [Supermetrics](https://docs.supermetrics.com/docs/facebook-ads-reach-and-attribution-changes-june-10-2025). - Klaviyo: [Understanding message conversion tracking](https://help.klaviyo.com/hc/en-us/articles/115005248128). Checked October 2026. - WebKit: [Intelligent Tracking Prevention 2.1](https://webkit.org/blog/8613/intelligent-tracking-prevention-2-1/). Apple: [Link Tracking Protection](https://www.apple.com/newsroom/2023/06/apple-announces-powerful-new-privacy-and-security-features/). ## Where Sporetag fits Sporetag reads orders straight from Shopify or Stripe, then shows each ad platform's own number beside its own count, so you can see the gap instead of guessing at it. More: https://sporetag.com/how-it-works --- # Meta ads vs Shopify: why purchases don't match > Meta Ads Manager shows more (or fewer) purchases than Shopify. The six causes, how to measure your own gap, and which number to use for budget calls. Source: https://sporetag.com/guides/meta-ads-vs-shopify-sales By the Sporetag team. Updated October 23, 2026. Ads Manager shows more purchases this week than Shopify credits to Facebook and Instagram. Another week it flips, and Meta shows fewer. Both reports are working as designed. They answer different questions with different data. This guide lists the six causes, in the order they usually matter, then shows how to measure your own gap and which number to use when you move budget. ## Meta and Shopify answer different questions **Meta asks:** did a person who clicked or saw one of our ads buy within the attribution window? It credits the ad if so, even if that buyer also came through Google, email and a direct visit before buying. **Shopify asks:** which marketing channel brought the visit that led to the order? By default it uses "last non-direct click" ([Shopify](https://www.shopify.com/blog/marketing-insights)), so only one channel gets each order, and a buyer who last came from a Google search counts for Google, not Meta. Neither is wrong. They are measuring different things. ## Six reasons the numbers differ ### 1. View-through and engage-through purchases Meta's default setting for website conversion campaigns counts purchases within 7 days of a link click, within 1 day of a view, and, since 2026, within 1 day of a non-link interaction such as a like or a comment ([Jon Loomer, March 2026](https://www.jonloomer.com/meta-ads-attribution-2026/)). Shopify cannot see an ad view at all. Every view-through purchase in Meta is a purchase Shopify credits elsewhere or to direct. In Ads Manager, use **Compare attribution settings** to split the column by click, view and engage-through. That one step often explains most of the gap. ### 2. Both platforms claim the same sale A buyer who clicked a Meta ad on Monday and a Google ad on Thursday counts in both ad platforms. Shopify gives the order to one channel. Add every platform's purchases together and the sum will be higher than your order count. The same overlap inflates leads and signups: see [Meta Ads cost per lead](https://sporetag.com/guides/meta-ads-cost-per-lead). ### 3. Cross-device matching Meta can match a purchase on a laptop to an ad click on a phone when the buyer is logged in to Facebook or Instagram on both. Shopify sees the laptop session only and credits whatever brought it, often direct or brand search. This pushes Meta's count above Shopify's. ### 4. Lost click ids and lost pixels The other direction: Meta counts fewer purchases than really came from its ads. - The Meta pixel is blocked by an ad blocker or declined in a consent banner, and no server event was sent. - The buyer opened the ad link in Safari Private Browsing, where Safari strips known click ids such as `fbclid` ([Apple](https://www.apple.com/newsroom/2023/06/apple-announces-powerful-new-privacy-and-security-features/)). - The purchase was more than 7 days after the click, outside the window. The [Conversions API](https://sporetag.com/guides/meta-conversions-api-explained) recovers many of these by sending each paid order from a server, with the buyer's hashed email and phone so Meta can match it. ### 5. Dates and time zones Meta and Shopify can put the same purchase on different days. Check that the ad account and the store use the same time zone, and compare at least a full week, since a click on Sunday night and a purchase on Monday morning land in different days in different tools. Meta's reporting date rules for website conversions also changed in 2025 ([Supermetrics](https://docs.supermetrics.com/docs/facebook-ads-reach-and-attribution-changes-june-10-2025)), so compare like with like when you look at older data. ### 6. Duplicate or missing events - A purchase event that fires on every load of the thank-you page counts reloads as new purchases. - A browser event and a server event without a shared `event_id` both count ([Meta](https://developers.facebook.com/docs/marketing-api/conversions-api/deduplicate-pixel-and-server-events)). - Since August 2026, script tags on Shopify's order status page no longer run for any store ([Shopify](https://shopify.dev/docs/apps/build/online-store/script-tag-deprecation/order-status)). A purchase tag still installed there sends nothing. Shopify points tracking to web pixels and the Customer events settings instead. In Events Manager, the **Event deduplication** and **Event match quality** views show whether browser and server events are being merged and matched. ## Measure your own gap 1. Pick a full 28-day period that ended at least 7 days ago, so late purchases have come in. 2. In Ads Manager, read purchases with **7-day click** only, no view or engage-through. 3. In Shopify, export orders for the same dates with their first and last visit sources. 4. Count the orders where any visit came from Meta, with `fbclid` on the landing page or `utm_source=facebook` or `instagram`. 5. Compare: Meta 7-day click against Shopify orders with a Meta touch. These two numbers should be much closer than the raw totals. Whatever gap is left is your measurement loss plus cross-device matches. Write it down and recheck monthly. A steady gap can be planned around. A sudden jump means something broke. ## Which number to use for budget - **For how much you sold**, always Shopify. - **For comparing Meta with other channels**, use one independent view with one rule for every channel: Shopify's own reports, an analytics tool, or an attribution tool that reads Shopify orders. - **For whether a Meta campaign is getting better**, use Meta's numbers as a trend. Meta optimizes delivery on its own count, so its relative changes are meaningful even when its total is higher than Shopify's. - **For total efficiency**, divide Shopify revenue by total ad spend: the [marketing efficiency ratio](https://sporetag.com/glossary/mer). It cannot double count. ## Common questions ### Why does Meta show more purchases than Shopify? Usually view-through and engage-through purchases, the same order claimed by other platforms too, and purchases Meta matched across devices. Switch Ads Manager to 7-day click only to see how much of the gap is view-through. ### Why does Meta show fewer purchases than Shopify credits to Facebook? The pixel was blocked or declined, click ids were stripped, or the purchase came after Meta's window. Sending purchases through the Conversions API with hashed customer details recovers part of it. ### Which attribution setting should I use in Ads Manager? For comparing with Shopify, read 7-day click. For optimizing, Meta's own default is reasonable. Changing the setting on an ad set changes what Meta optimizes for, not just how it reports, so test it on one ad set first. ### Does Shopify's Facebook channel app fix this? It installs the pixel and sends server events for you, which closes part of the loss. It cannot make the two tools use the same attribution rule, so the totals will still differ. ## Sources - Shopify: [Marketing insights and attribution models](https://www.shopify.com/blog/marketing-insights), [Order status script tags](https://shopify.dev/docs/apps/build/online-store/script-tag-deprecation/order-status). Checked October 2026. - Meta: [Deduplicate pixel and server events](https://developers.facebook.com/docs/marketing-api/conversions-api/deduplicate-pixel-and-server-events). Checked October 2026. - Meta attribution settings as of 2026: [Jon Loomer](https://www.jonloomer.com/meta-ads-attribution-2026/). Reporting date change: [Supermetrics](https://docs.supermetrics.com/docs/facebook-ads-reach-and-attribution-changes-june-10-2025). - Apple: [Link Tracking Protection](https://www.apple.com/newsroom/2023/06/apple-announces-powerful-new-privacy-and-security-features/). ## Where Sporetag fits Sporetag reads each Shopify order, matches it to the ad set that brought the visit, and shows Meta's own purchase count beside it, so you see both numbers in one table. More: https://sporetag.com/platforms/meta --- # GA4 not tracking conversions: a checklist that finds the cause > Key events missing in GA4? Work through ten checks in order, from the event never firing to consent, filters, processing delays and Google Ads imports. Source: https://sporetag.com/guides/ga4-not-tracking-conversions By the Sporetag team. Updated October 23, 2026. When GA4 shows zero conversions, or far fewer than you expect, the cause is almost always in one of three places: the event never reaches GA4, it arrives but is not marked as a [key event](https://sporetag.com/glossary/key-event), or it is counted but you are looking in the wrong report or too soon. Work through the checks below in order. Each one rules out a layer. In 2024 Google renamed GA4 "conversions" to "key events". The word "conversion" now means an action used to measure ads, such as one imported into Google Ads ([Google](https://support.google.com/analytics/answer/13965727)). If a guide tells you to find **Conversions** in the GA4 admin, look for **Key events**. ## 1. Does the event fire at all? Open **Admin**, **DebugView**, and turn on debug mode for your own browser: install Google's Tag Assistant, or use **Preview** in Google Tag Manager. Then do the action yourself: send the form, finish a test purchase. - **The event appears in DebugView.** Good. Move to check 3. - **Nothing appears.** The tag or trigger is the problem. Go to check 2. **Realtime** works too, but DebugView shows each event with its parameters, which you will need for later checks. ## 2. Why the event does not fire - **The trigger never matches.** A Tag Manager trigger on "Page path equals /thank-you" misses `/thank-you/` and `/thank-you?order=1042`. Use "contains" or a regular expression, and check what the URL really is after a form sends. - **The form does not load a new page.** Many form tools show a success message in place. A pageview trigger never fires. Use the form tool's own callback, a form submission trigger, or the tool's built-in GA4 integration. - **The form is in an iframe.** Embedded booking and form widgets (Calendly, Typeform, HubSpot and others) run on another domain. Your page's tag cannot see inside the frame. Use the vendor's GA4 integration or its message events. - **The checkout runs on another domain.** Shopify's checkout does not run theme code, and Shopify's order status page stopped running script tags in August 2026 ([Shopify](https://shopify.dev/docs/apps/build/online-store/script-tag-deprecation/order-status)). Use Shopify's Google channel app or a web pixel under **Settings**, **Customer events**. - **The tag is blocked until consent.** If your banner holds the GA4 tag until the visitor accepts, declined visits never send anything. Test with consent accepted. - **The tag is not published.** Changes in Tag Manager do nothing until you click **Submit** and publish the container. The free [tag checker](https://sporetag.com/tools/tag-checker) shows which analytics and ad tags your live home page actually loads, with their ids. ## 3. Is the event name exactly right? GA4 event names are case sensitive: `generate_lead` and `Generate_Lead` are two different events ([Google](https://support.google.com/analytics/answer/13316687)). A key event marked as `purchase` will never count `Purchase`. Compare the name in DebugView, letter by letter, with the name in **Admin**, **Events**. ## 4. Is it marked as a key event? In **Admin**, **Data display**, **Events**, find the event and turn on **Mark as key event**. If the event has not arrived yet, create the key event by name under **Key events**, **New key event**. Marking an event only counts it from that moment on. GA4 does not go back and count past events as key events. If you marked it today, expect zero for every day before today. ## 5. Have you waited long enough? Standard GA4 properties typically take 12 hours to process a day's data, and Google says daily data is ready in reports around mid-afternoon the next day in the property's time zone ([Google](https://support.google.com/analytics/answer/11198161)). Attribution credit for key events can still change for up to 12 days after the event. Realtime and DebugView are the only places to see today's events today. ## 6. Are you reading the right report? - **Traffic acquisition** splits key events by the session's source. **User acquisition** splits them by the source that first brought the user. The same key event shows under different channels in each. - A comparison or segment left on from an earlier visit can hide everything. Clear filters in the report's top bar. - In Explore, a date range that ends today shows partial data for today. ## 7. Is data being filtered out? Check **Admin**, **Data collection and modification**, **Data filters**. An internal traffic filter set to **Active** drops every event from matching IP addresses, including your own test purchases. A developer traffic filter drops events sent in debug mode. That is why test events can appear in DebugView and still never reach reports. ## 8. Is data thresholding hiding small numbers? When Google signals or user-provided data is on, GA4 can withhold rows with small counts from reports to protect identity. A key event with a handful of hits can show as missing. Look for a warning icon in the report header. Switching the reporting identity to device-based, under **Admin**, **Reporting identity**, can bring the rows back, because thresholds are tied to Google signals and user-provided data. ## 9. Is consent mode reducing the count? With consent mode, visitors who decline analytics cookies send cookieless pings or nothing. GA4 can model the missing behavior, but only for properties that collect at least 1,000 events a day with analytics storage denied for at least 7 days, and have at least 1,000 daily users who granted consent on at least 7 of the previous 28 days ([Google](https://support.google.com/analytics/answer/11161109)). A smaller site gets no modeling, so declined visits are simply not counted. ## 10. Missing in Google Ads, not GA4? - The GA4 property and the Google Ads account must be linked, and the key event imported in Google Ads under **Goals**, **Conversions**, **Summary**, **New conversion action**, **Import**, **Google Analytics 4 properties**. - Imported GA4 conversions can take up to a day or more to appear, and Google Ads puts them on the date of the ad click, not the date of the conversion ([Google](https://support.google.com/google-ads/answer/9549009)). - Auto-tagging must be on in Google Ads, so the `gclid` reaches your site. A redirect that drops query strings breaks it. Check that a test click lands with `gclid=` still in the address bar. ## A five-minute test you can repeat 1. Open your site in a private window with consent accepted, from a link with `?utm_source=test&utm_medium=test&utm_campaign=ga4_check`. 2. Complete the action. 3. Confirm the event in DebugView or Realtime within a minute, with source `test`. 4. The next afternoon, confirm the key event in **Traffic acquisition** under source `test`. If step 3 passes and step 4 fails, the problem is a filter, thresholding or the key event setting. If step 3 fails, it is the tag. ## Common questions ### Why does GA4 show the event but zero key events? The event is not marked as a key event, the name differs in case, or it was marked after the events you are looking at. Marking only counts new events. ### How long does GA4 take to show key events? Realtime and DebugView show them within seconds. Standard reports typically have the full previous day by the next afternoon, and attribution credit can still change for up to 12 days. ### Why are my GA4 conversions lower than Shopify orders? Some buyers block the tag or decline consent, Shopify's checkout pages do not run theme scripts, and GA4 credits sales by its own rules. See [why analytics numbers never match](https://sporetag.com/guides/why-analytics-numbers-dont-match). ### Why does Google Ads show different conversions than GA4? Google Ads puts conversions on the click date and counts only paths with a Google Ads click, while GA4 reports by event date across every channel with its own attribution model. ## Sources - Google Analytics Help: [Conversions vs key events](https://support.google.com/analytics/answer/13965727), [Event naming rules](https://support.google.com/analytics/answer/13316687), [Data freshness](https://support.google.com/analytics/answer/11198161), [Consent mode behavioral modeling](https://support.google.com/analytics/answer/11161109). Checked October 2026. - Google Ads Help: [Conversions by time](https://support.google.com/google-ads/answer/9549009). Checked October 2026. - Shopify: [Order status script tags](https://shopify.dev/docs/apps/build/online-store/script-tag-deprecation/order-status). Checked October 2026. ## Where Sporetag fits In Sporetag a goal is a one-tap template (someone buys, fills in a form, books or calls) that counts from the moment you save it, and the Goals tab shows each goal's latest hit. More: https://sporetag.com/docs/custom-events-and-goals --- # Direct traffic: what (direct) / (none) really means > Direct traffic is every visit that arrived with no referrer and no tag. Where it really comes from, why it grows, and five ways to shrink it. Source: https://sporetag.com/guides/direct-traffic-explained By the Sporetag team. Updated October 23, 2026. "Direct" sounds like people typing your address. Some of it is. Most of it is not. In analytics, direct traffic is a leftover: every visit where the tool found no [referrer](https://sporetag.com/glossary/referrer), no UTM tag and no other clue about where the visitor came from. In GA4 that leftover is source `(direct)` and medium `(none)` ([Google](https://support.google.com/analytics/answer/9756891)). In Sporetag and most privacy-friendly tools it is "Direct / None". The label is the same idea: we do not know. ## Where direct traffic really comes from - **Typed addresses and bookmarks.** The real direct visits. Usually returning customers and people who heard your name somewhere you cannot track, such as a podcast or a conversation. - **Apps.** A link tapped in an email app, a chat app, a desktop app or a PDF often opens the browser with no referrer at all. An email newsletter without UTM tags mostly shows up as direct. - **In-app browsers.** Instagram, Facebook, TikTok and other apps open links in their own browser. Depending on the app and version, the visit may arrive with no referrer. - **HTTPS to HTTP.** Browsers send no referrer from a secure page to an insecure one under the default referrer policy ([MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Referrer-Policy)). If your site still loads over plain HTTP anywhere, links from secure sites lose their source. - **A strict referrer policy on the linking site.** A site can choose `no-referrer` for every outgoing link. Some webmail and privacy-focused sites do. - **Lost tags.** A redirect that drops the query string removes your UTM tags and click ids on the way. So do some link shorteners and some "clean URL" settings. - **Bots** that request pages with no referrer, when a tool does not filter them. ## What the referrer actually carries Under the default policy, `strict-origin-when-cross-origin`, a link from one site to another sends only the origin, such as `https://news.example.com/`, not the full page address ([MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Referrer-Policy)). So even when the referrer arrives, you know the site, not the article or the post. That is why a link you control should carry [UTM parameters](https://sporetag.com/guides/utm-parameters): they name the exact campaign and placement, and they survive where the referrer does not. ## Why direct grows over time - More traffic arrives through apps, where referrers are least reliable. - Browsers trim more. Safari strips known click ids from links opened from Mail, Messages and Private Browsing ([Apple](https://www.apple.com/newsroom/2023/06/apple-announces-powerful-new-privacy-and-security-features/)). - Brand grows. More people know your name and type it. A rise in direct is not bad by itself. A sudden jump on one day usually is a tracking change: a redirect, a site migration, a new consent setup, or a campaign sent without tags. ## How attribution tools treat direct Most models refuse to give direct the credit when they know of anything else. GA4's models exclude direct visits from receiving credit unless every visit on the path was direct ([Google](https://support.google.com/analytics/answer/10596866)). Shopify's default model is "last non-direct click" for the same reason ([Shopify](https://www.shopify.com/blog/marketing-insights)). A buyer who clicked an ad last week and typed your address today counts for the ad, if the tool still remembers the ad click. That memory is the weak point. In a cookieless tool, the next day's visit is a new visitor, so it shows as direct. In a tool with a first-party id, Safari's 7-day cap on cookies set by script can end that memory early ([WebKit](https://webkit.org/blog/8613/intelligent-tracking-prevention-2-1/)). ## Five ways to shrink direct traffic 1. **Tag every link you control.** Email, [SMS](https://sporetag.com/guides/track-sms-link-clicks), social bios, QR codes, partner links, podcast show notes. Any link without UTM tags that leaves an app becomes direct. 2. **Use short links for anything people type or scan.** A [short link](https://sporetag.com/glossary/short-link) counts the click itself, then forwards with the tags, so a podcast mention or a printed code has a source even if the visit loses its referrer. 3. **Fix redirects.** Test your main landing pages with `?utm_source=test` and confirm the tag is still there after every redirect, including `http` to `https` and `www` to the bare domain. 4. **Serve every page over HTTPS** and keep a referrer policy no stricter than the default. 5. **Read the in-app browser.** Some tools, Sporetag among them, name the source from the in-app browser or the Android app that opened the link when no referrer arrives. Check whether yours does before you assume direct means typed. ## What not to do - **Do not tag your own internal links.** A UTM tag on a link from your blog to your pricing page replaces the real source of that visit with your own tag. - **Do not treat direct as "brand".** It is a mix of brand, untagged campaigns and lost sources. Compare it with branded search to see how much is brand. - **Do not chase zero.** Some visits will always arrive without a clue. The goal is a direct share that is stable and explained. ## Common questions ### What is direct / none in GA4? It is GA4's label for a session with no referrer, no campaign tags and no auto-tagging click id. Source is `(direct)` and medium is `(none)`. ### Is direct traffic good or bad? Neither. It includes loyal customers typing your address, which is good, and campaigns that lost their tags, which is a tracking problem. Read the landing pages: direct visits landing deep on a campaign page are usually lost tags. ### Why did direct traffic suddenly go up? Look for a change on that day: a site migration, a new redirect, a consent banner, an email sent without tags, or a spike of bots. A gradual rise is normal. A step change is almost always technical. ### Does email traffic show as direct? Often, yes. Desktop and mobile email apps frequently send no referrer. Tag every email link with `utm_source` and `utm_medium=email`. ## Sources - Google Analytics Help: [Default channel group](https://support.google.com/analytics/answer/9756891), [Get started with attribution](https://support.google.com/analytics/answer/10596866). Checked October 2026. - MDN: [Referrer-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Referrer-Policy). Checked October 2026. - Shopify: [Marketing insights](https://www.shopify.com/blog/marketing-insights). Apple: [Link Tracking Protection](https://www.apple.com/newsroom/2023/06/apple-announces-powerful-new-privacy-and-security-features/). WebKit: [ITP 2.1](https://webkit.org/blog/8613/intelligent-tracking-prevention-2-1/). ## Where Sporetag fits Sporetag recovers part of what other tools call direct by reading the app a visit came from: Android app referrers, in-app browsers such as Instagram and TikTok, and the platform behind an ad click id. More: https://sporetag.com/how-it-works --- # GA4 "(not set)": every cause and how to fix it > Why GA4 shows (not set) for landing page, source, medium and campaign, how to tell which cause you have, and the fix for each one. Source: https://sporetag.com/guides/ga4-not-set By the Sporetag team. Updated October 23, 2026. "(not set)" is not a source, a page or a campaign. It is the placeholder GA4 writes when it received no value for a dimension ([Google](https://support.google.com/analytics/answer/13504892)). So the question is never "what is (not set)?" but "why did this value never arrive?" The answer depends on which dimension you are looking at. This guide goes dimension by dimension, with a test for each cause. It sits next to [why analytics numbers never match](https://sporetag.com/guides/why-analytics-numbers-dont-match): (not set) is one of the ways GA4 parts ways with your other tools. ## First, find out which (not set) you have Open the report where you saw it and note the dimension. The causes barely overlap: | Where you see (not set) | What is missing | Most common cause | |---|---|---| | Landing page | A `page_view` in the session | The session started on an event, not a pageview | | Session source / medium | The `session_start` event | Tag order, or consent mode set up wrong | | Session campaign | Campaign information | A tag missing `utm_campaign`, or untagged traffic | | Google Ads reports (campaign, keyword) | A link from the click to the account | Ads not linked, or auto-tagging off | | A custom dimension | The parameter on that event | Registered less than 24 hours ago, or never sent | Two lookalikes are different problems. **(other)** is GA4 folding rare values into one row when a table passes its row limit ([Google](https://support.google.com/analytics/answer/13331684)). **(data not available)** is a related placeholder that you usually cannot reduce ([Google](https://support.google.com/analytics/answer/13504892)). ## Landing page: (not set) GA4 shows (not set) as the [landing page](https://sporetag.com/glossary/landing-page) when a session has no `page_view` event ([Google](https://support.google.com/analytics/answer/13504892)). The landing page is read from the first pageview, so a session without one has nothing to show. How a session ends up with no pageview: - **A tab left open past the timeout.** A GA4 [session](https://sporetag.com/glossary/session) ends after 30 minutes without activity by default ([Google](https://support.google.com/analytics/answer/9191807)). When the visitor comes back to the open tab and scrolls or clicks, that event starts a new session. No page loaded, so no `page_view`. - **Events fired before the pageview.** A Tag Manager event tag that fires before the Google tag sends its config sends an event with no session context. Google's advice is to initialize the Google tag before any event ([Google](https://support.google.com/analytics/answer/14847402)). - **Pageviews turned off.** Some single-page app setups disable the automatic `page_view` and send their own, and one route never sends it. - **Server events.** Events sent with the Measurement Protocol create activity on the server, where no page was viewed. **Fix:** in Tag Manager, fire the Google tag on **Initialization - All Pages** and every event tag after it ([Google](https://support.google.com/tagmanager/answer/7679319)). Then check single-page app routes in DebugView: each route change should send one `page_view`. A small share of (not set) from returning tabs is normal and cannot be removed. ## Session source / medium: (not set) Session source and medium read (not set) when the session has no `session_start` event ([Google](https://support.google.com/analytics/answer/13504892)). Those sessions also fall into **Unassigned** in the default channel group, because no channel rule matches them. The causes Google names: 1. **The Google tag fires too late.** In Tag Manager, the Google tag should use the **Initialization - All Pages** trigger, not a later one. 2. **Consent mode set up with the wrong command.** Using `default` to record the visitor's answer, instead of `update`, means the event that carries `session_start` is lost. 3. **Denied events after a yes.** Sending more events with denied consent after the visitor agreed makes GA4 treat them as a separate session with no `session_start`. Google also notes a quirk of Google Search: sessions that carry the `srsltid` parameter but no google.com referrer can show (not set). That happens when people share a modified link, and those sessions are not counted as organic ([Google](https://support.google.com/analytics/answer/13504892)). **Fix:** move the Google tag to the Initialization trigger, then review your consent banner's integration with [consent mode](https://sporetag.com/glossary/consent-mode). The banner should call `gtag('consent', 'default', ...)` once, before the Google tag loads, and `gtag('consent', 'update', ...)` when the visitor answers. ## Session campaign: (not set) Campaign is (not set) for every visit that carried no campaign. Organic, referral and direct visits have no campaign by nature, so a large (not set) row here is expected. It becomes a problem when paid traffic lands in it: - **Tags missing a value.** A link with `utm_source` and `utm_medium` but no `utm_campaign` arrives with a source and no campaign. Google lists incomplete or incorrect UTM tags as a cause ([Google](https://support.google.com/analytics/answer/13504892)). - **Tags stripped by a redirect.** A redirect that drops the query string removes the [UTM parameters](https://sporetag.com/guides/utm-parameters) and the click id, and the visit loses its campaign and often its source too. **Fix:** use all three required tags on every link you control, written the same way every time. Test landing pages with `?utm_source=test&utm_medium=test&utm_campaign=test` and confirm all three survive every redirect. ## Google Ads reports: (not set) In GA4's Google Ads reports, (not set) means GA4 could not tie the session to a click in a linked account. Google lists the causes ([Google](https://support.google.com/analytics/answer/13504892)): - Google Ads and GA4 are not linked. - Auto-tagging is off, so clicks arrive without a [gclid](https://sporetag.com/glossary/gclid). - Another Google Ads account advertises your site and is not linked to this property. Its clicks carry a gclid that GA4 cannot map. - Manual UTM tags that are incomplete or wrong. **Fix:** link every Google Ads account that sends traffic, turn on auto-tagging in each, and check that the `gclid` reaches your landing page. If a site or plugin strips unknown query parameters, the gclid goes with them. ## Custom dimensions: (not set) Two causes cover nearly every case ([Google](https://support.google.com/analytics/answer/13504892)): - **It is new.** For the first 24 hours after you register a custom parameter, its value can show as (not set). - **The event does not carry it.** A custom dimension is per event. A report that mixes events, such as `page_view` with `session_start`, shows (not set) for the events that never had the parameter. Content groups do the same with automatically collected events, which do not accept `content_group`. **Fix:** wait a day after registering. Then filter the report to the event that sends the parameter, and confirm the parameter in DebugView. ## A worked example Example numbers, made up for illustration. A store sees 1,240 sessions in a week with landing page (not set), out of 18,600. Its steps: 1. **Break down by event name.** Most (not set) sessions start with `user_engagement` or `scroll`, not `page_view`. That points to sessions restarted in an open tab. 2. **Break down by device.** The share is far higher on desktop, where tabs stay open all day. That fits. 3. **Check Tag Manager.** The Google tag fires on **All Pages**, after two event tags on **Initialization**. Those event tags fire before the config. 4. **Fix and compare.** After moving the Google tag to **Initialization - All Pages**, the share falls the next week. The rest is returning tabs, which is expected. ## How to keep (not set) small - Fire the Google tag first, on the Initialization trigger. - Send consent defaults before the tag, and updates with `update`. - Tag every link you control with `utm_source`, `utm_medium` and `utm_campaign`. - Link every Google Ads account and keep auto-tagging on. - After any site change, open a landing page with test tags and read DebugView. Most of the same habits also shrink [direct traffic](https://sporetag.com/guides/direct-traffic-explained), since a lost tag shows up in one or the other. ## Common questions ### What does (not set) mean in GA4? It is a placeholder for "no value received". GA4 shows it when a dimension had no data for that row: no pageview for the landing page, no `session_start` for the source, no campaign tag for the campaign. ### Is (not set) the same as direct traffic? No. Direct is a source: GA4 received the session and found no referrer, tag or click id. (not set) means a value never arrived at all, often because of how the tag was set up. ### Why is my landing page (not set) in GA4? The session had no `page_view` event. The usual cause is a visitor returning to an open tab after the 30-minute timeout, so a scroll or a click started the new session. Event tags firing before the Google tag cause it too. ### Why does Unassigned go up with (not set)? A session with source and medium (not set) matches no channel rule, so it lands in Unassigned. Fix the source and Unassigned shrinks with it. ### Can I remove (not set) from old reports? No. GA4 processes data as it arrives. Fixes apply from the day you make them. ## Sources - Google Analytics Help: [What the value (not set) means in your reports](https://support.google.com/analytics/answer/13504892), [Tagging best practices to avoid unassigned, (not set), and direct traffic issues](https://support.google.com/analytics/answer/14847402), [About Analytics sessions](https://support.google.com/analytics/answer/9191807), [About the (other) row](https://support.google.com/analytics/answer/13331684). Checked October 2026. - Tag Manager Help: [Page view triggers](https://support.google.com/tagmanager/answer/7679319). Checked October 2026. ## Where Sporetag fits In Sporetag a visit takes its source and landing page from its first pageview, a visitor who clicks on within 1.5 seconds keeps the page they landed on, and a visit with no source shows as Direct / None, never as a blank. More: https://sporetag.com/docs/tracking-health --- # Bot traffic in analytics: how to spot it and filter it > How GA4 and other tools filter bots, the patterns that give bots away in your reports, and what you can do about the bots that get through. Source: https://sporetag.com/guides/bot-traffic-in-analytics By the Sporetag team. Updated October 23, 2026. A share of every site's traffic is software: search crawlers, uptime monitors, link previews, price scrapers, AI agents and click fraud. Analytics tools try to keep it out, each with its own rules, so the same site shows different numbers in each tool. That is one of the reasons [analytics numbers never match](https://sporetag.com/guides/why-analytics-numbers-dont-match). This guide explains how filtering works, how to find the [bot traffic](https://sporetag.com/glossary/bot-traffic) that got through, and what you can do about it. ## Kinds of bots, by how easy they are to catch | Kind | Examples | How it identifies itself | |---|---|---| | Declared crawlers | Googlebot, Bingbot, AI crawlers | Names itself in the user agent | | Link previews | Chat apps and social sites fetching a card | Usually names itself | | Monitors and audits | Uptime checks (see [uptime monitoring for client sites](https://sporetag.com/guides/uptime-monitoring-for-agencies)), Lighthouse, SEO crawlers | Usually names itself | | Headless browsers | Scrapers, test scripts | Often hides, but may report automation | | Disguised bots | Click fraud, spam, some scrapers | Pretends to be a normal browser | The first three are easy. Many of them never run JavaScript, so a script-based tool never sees them at all. The last two are the problem. ## How tools filter bots **GA4** excludes known bots and spiders automatically, using Google's own research and the IAB/ABC International Spiders and Bots List. You cannot turn it off, and you cannot see how much it removed ([Google](https://support.google.com/analytics/answer/9888366), [IAB](https://www.iab.com/guidelines/iab-abc-international-spiders-bots-list/)). GA4 has no setting for your own bot rules beyond internal and developer traffic filters. **CDNs** such as Cloudflare keep a list of verified bots: bots that say who they are in a way that can be checked, such as a published IP list or a cryptographic signature ([Cloudflare](https://developers.cloudflare.com/bots/concepts/bot/verified-bots/)). Some plans also give each request a bot score from 1 to 99, where 1 means almost certainly automated ([Cloudflare](https://developers.cloudflare.com/bots/concepts/bot-score/)). **Script timing** catches more. A tool that waits until the page has been visible for a moment before counting misses bots that load a page and leave, and tabs that open in the background and close unseen. No method catches everything. A bot that runs a real browser from a home network, waits, and scrolls looks like a person to every tool. ## The signs of bots in your reports Look for traffic that no group of real people would make: - **A spike from one city or one network** with no campaign behind it. - **One page, zero seconds.** Hundreds of visits to one page, with a bounce rate near 100% and no time on the page. - **A flat line through the night.** People sleep; schedulers do not. - **Odd screen sizes or old browsers** in large numbers, such as one exact resolution, or a browser version years out of date. - **Visits from cloud networks** such as AWS, Google Cloud or DigitalOcean. Real people do browse through VPNs hosted there, so this is a clue, not proof. - **Referrers you never heard of,** especially ones promoting SEO services. That is referral spam. - **Form spam or fake signups** in the same hours as a traffic spike. ### Ghost spam is mostly gone In older Universal Analytics properties, spammers sent fake hits straight to Google with your tracking id, without visiting your site. GA4's Measurement Protocol requires an API secret that only your property has ([Google](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference)), which ended most of that. Spam that shows up today usually came through your real pages. ## A worked example Example numbers, made up for illustration. A shop's visits jump from about 900 a day to 2,600 on a Tuesday. Steps to find the cause: 1. **Break down by page.** 1,650 of the extra visits land on `/products/brass-lamp`. No campaign links there. 2. **Break down by country and city.** All of them come from one city where the shop has never sold. 3. **Look at engagement.** Bounce rate 99%, and no time on the page. 4. **Check the hour.** The visits arrive at an even rate from 01:00 to 05:00 local time. That is a scraper checking a product page, probably a price monitor. The fix is at the server or CDN, not in analytics: block or challenge that traffic. For reports, compare the week with that city excluded, and note the spike in the client report so nobody reads it as demand. ## What you can do 1. **Block at the edge.** Your CDN or host sees every request, not just the ones that run your script. Bot rules there stop scrapers from costing you bandwidth too. 2. **Exclude in reports, not in raw data.** Keep the raw numbers and build a comparison or segment that leaves out the bad city, network or referrer. You can undo a segment; you cannot undo deleted data. 3. **Protect forms.** A challenge such as Cloudflare Turnstile or reCAPTCHA stops fake signups that would otherwise count as conversions. 4. **Watch your ad clicks.** Google filters invalid clicks, including automated traffic, and does not charge for them ([Google](https://support.google.com/google-ads/answer/42995)). If ad clicks spike without visits or sales, ask the platform for a review. 5. **Judge by outcomes.** Bots rarely buy. A source with visits and no sales, ever, deserves a closer look. ## How Sporetag filters bots Sporetag's rules are in its code and its help article on [bot filtering](https://sporetag.com/docs/bot-filtering): - **Never recorded:** a user agent that names a crawler, a link preview, a monitor, a headless browser or an HTTP library; an empty user agent or a bare `Mozilla/5.0`; and verified bots. - **Never sent:** the script does not run in browsers that report `navigator.webdriver`, which most automation tools set. - **Counted only when seen:** a pageview goes out after the tab has been visible for 1.5 seconds, or half a second if the visitor leaves sooner. - **Marked and left out of the numbers:** a user agent that names no browser and no operating system, and a low bot score when the network provides one. - **Marked and still counted:** visits from cloud and hosting networks, because people on VPNs browse from them too. Short links follow the same user agent rules. A browser prefetching a link, or a `HEAD` request checking it, is not counted as a click. ## Common questions ### How do I know if my website traffic is bots? Look for patterns people do not make: a spike on one page from one city, near 100% bounce with no time on the page, an even rate through the night, or many visits from cloud networks. Bots rarely buy, so a source with traffic and no sales is a clue. ### Does GA4 filter bot traffic? Yes, known bots and spiders are excluded automatically, using Google's research and the IAB/ABC list. You cannot turn it off or see how much was removed, and it does not catch bots that pass as normal browsers. ### Why does one tool show more visitors than another? Each tool filters bots with its own rules, and script-based tools miss bots that do not run JavaScript. A tool that counts server requests sees far more bots than one that counts pageviews from a script. ### Can I remove bot traffic from past reports? Most tools do not delete it, but you can exclude it in a segment or comparison. Filter by the city, network, page or referrer that gives the bots away. ### Is referral spam harmful? It does not harm your site, but it pollutes reports and invites you to visit the spammer's site. Do not visit it. Exclude it in your reports. ## Sources - Google Analytics Help: [Known bot-traffic exclusion](https://support.google.com/analytics/answer/9888366). Google for Developers: [Measurement Protocol reference](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference). Checked October 2026. - IAB: [IAB/ABC International Spiders and Bots List](https://www.iab.com/guidelines/iab-abc-international-spiders-bots-list/). Checked October 2026. - Cloudflare: [Verified bots](https://developers.cloudflare.com/bots/concepts/bot/verified-bots/), [Bot scores](https://developers.cloudflare.com/bots/concepts/bot-score/). Checked October 2026. - Google Ads Help: [Invalid clicks](https://support.google.com/google-ads/answer/42995). Checked October 2026. ## Where Sporetag fits Sporetag drops known bots, automated browsers and link prefetches before they are counted, marks visits from cloud networks without dropping them, and counts a pageview only after the tab has been visible. More: https://sporetag.com/docs/bot-filtering --- # Cross-domain tracking: checkouts, booking tools and iframes > Why a visitor who moves to a checkout, a booking tool or an embedded form loses their source, and how to keep the credit with the ad that brought them. Source: https://sporetag.com/guides/cross-domain-tracking By the Sporetag team. Updated October 23, 2026. A visitor clicks your ad, lands on your site, then pays on `checkout.stripe.com`, books on `calendly.com`, or fills in a form that lives inside an iframe from another company. At that moment the journey crosses a domain line. Browsers keep cookies and storage per site, so on the other side the visitor is a stranger, and on the way back your analytics may think they arrived from the checkout. This guide covers the three cases that break attribution most often, and the fix for each. It is one of the causes behind [analytics numbers that never match](https://sporetag.com/guides/why-analytics-numbers-dont-match). ## What breaks, exactly Two separate things go wrong: 1. **Identity.** A first-party cookie set on `yourshop.com` is not readable on `book.example.net`. A tool running on both sides sees two visitors. 2. **Source.** When the buyer returns from the payment page, the [referrer](https://sporetag.com/glossary/referrer) is the payment page. Without a rule, the return trip starts a new visit "from paypal.com", and the ad that brought the buyer loses the sale. Subdomains are different from separate domains. A cookie set for `yourshop.com` can be shared by `www.yourshop.com` and `shop.yourshop.com`. Two different domains, such as `yourshop.com` and `yourshop-store.com`, can never share one. ## Case 1: hosted checkouts and payment pages Stripe Checkout, PayPal, Klarna and similar services take the buyer to their own domain and send them back to your thank-you page. **Fix the source.** Tell your analytics the payment domain is part of the journey, not a referral. GA4 calls this the unwanted referrals list: matching domains get `ignore_referrer=true` on their events, so the session keeps its original source. Google names third-party payment processors as the main use ([Google](https://support.google.com/analytics/answer/10327750)). **Fix the sale.** The thank-you page can fail: buyers close the tab before it loads, and some payment methods confirm later. Count the sale from the server too, with a shared order id so it is counted once. With Stripe specifically: - Put `{CHECKOUT_SESSION_ID}` in your success URL. Stripe replaces it with the real session id after payment, so your thank-you page knows which order it is ([Stripe](https://docs.stripe.com/payments/checkout/custom-success-page)). Use that id as the event id in the browser and on the server. - Stripe recommends fulfilling from the `checkout.session.completed` webhook, not the redirect alone, because a buyer can pay and lose connection before the page loads ([Stripe](https://docs.stripe.com/payments/checkout/custom-success-page)). - Payment Links can redirect to your own page too, and UTM tags on the payment link are added to the redirect address ([Stripe](https://docs.stripe.com/payment-links/post-payment)). ## Case 2: two domains you own A brand site on one domain and a shop or app on another is common. Here you want one visitor across both. GA4 does this with cross-domain measurement: you list the domains in the data stream, and GA4 adds a `_gl` parameter to links between them, which carries the visitor's id across ([Google](https://support.google.com/analytics/answer/10071811)). It only works when people move by clicking a link. Someone who types the second address starts fresh. A redirect that drops the query string drops `_gl` with it. The simplest fix is structural: put the second property on a subdomain of the first, such as `shop.yourbrand.com`, and the problem goes away for any tool that sets its cookie on the parent domain. ## Case 3: iframes and embedded tools Booking widgets, form builders and some checkouts are embedded in your page as an iframe from another domain. Code inside that iframe runs in a third-party context: - Safari blocks third-party cookies by default, and has since 2020 ([WebKit](https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/)). - Firefox gives third-party cookies a separate jar per site by default, with Total Cookie Protection ([MDN](https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Third-party_cookies)). - Chrome does not block them by default, so a setup that works in Chrome can fail in Safari and Firefox ([MDN](https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Third-party_cookies)). So do not track inside the iframe. Track on your own page, where your analytics already knows the visitor. Many embedded tools tell the parent page what happened through `postMessage`. Calendly's embed, for example, posts events such as `calendly.event_scheduled` to the parent window ([Calendly](https://developer.calendly.com/api-docs/overview/embedding/notifying-the-parent-window)). Listen for that event, check its origin, and count the conversion on your page. If the tool sends no events, count what happens after: a redirect to your own thank-you page, or a webhook from the tool to your server. ## A worked example Example numbers, made up for illustration. A course creator sells through Stripe Checkout and finds that `checkout.stripe.com` is her third biggest source of sales, with 31 of 140 sales in a month. 1. **The cause.** Buyers return from Stripe to `/thanks`, and the referrer is Stripe. Those visits start fresh. 2. **Fix the source.** She adds `checkout.stripe.com` to the payment hosts her analytics treats as her own site. 3. **Fix the sale.** Her success URL becomes `/thanks?session_id={CHECKOUT_SESSION_ID}`, and the thank-you page sends the purchase with the session id as its event id. Her server sends the same id from the webhook. 4. **The result.** Stripe drops out of the sources. The 31 sales move back to the ads and emails that brought those buyers, and none is counted twice. ## Common mistakes 1. **Adding your own domain to the referral list as a fix for everything.** It hides the symptom; find the page that loses the tag. 2. **Tracking inside an iframe** and trusting the numbers from Chrome only. 3. **Relying on the thank-you page alone** for sales. 4. **Different event ids** in the browser and on the server, so the same order counts twice. 5. **A redirect that drops parameters** between your domains. ## How Sporetag handles it - **Payment pages.** Sporetag knows common payment hosts such as PayPal, Stripe, Shopify checkout, Klarna and Square. Its tracking health check spots a payment page or your own domain starting visits, and **Count them as my site** fixes it in one tap. The visit carries on and the credit stays with the source that brought the buyer. - **Subdomains.** A site counts visits from its domain and every subdomain. In [90-day tracking](https://sporetag.com/docs/tracking-modes), the first-party id is set on the parent domain, so `shop.` and `www.` share it. - **Stripe Checkout.** Copy the `_st_id` cookie into the Checkout Session's `metadata.st_id`, and the [Stripe connector](https://sporetag.com/docs/stripe-connector) ties each sale to the visits before it. The connector uses the session id as the event id, so a browser event with the same id counts once. - **Embedded Calendly.** With the "Someone books or calls" goal on, a booking made inside an embedded Calendly widget counts. See [how to track Calendly bookings](https://sporetag.com/track/calendly). - **Two separate domains.** Sporetag has no link decorator between different domains today. Each domain is its own site, and a person moving between them is two visitors. ## Common questions ### What is cross-domain tracking? Keeping one visitor and one source as someone moves between two domains, such as your site and a checkout or booking tool. Without it, the second domain sees a new visitor, and the return trip can look like a referral. ### Why is PayPal or Stripe showing as a referral source? Buyers come back from the payment page to your thank-you page, so the referrer is the payment page. List those domains as part of your site in your analytics, so the visit keeps its original source. ### Do I need cross-domain tracking for subdomains? Usually not. A tool that sets its cookie on the parent domain shares it across subdomains. You need it for different domains. ### Can I track conversions inside an iframe? Not reliably. Safari and Firefox block or partition the cookies an iframe from another domain needs. Count the conversion on your own page, from an event the embedded tool posts, or from a redirect or webhook. ### Does cross-domain tracking work if people type the address? No. Methods like GA4's `_gl` parameter travel in the link. A typed address or a bookmark starts fresh. ## Sources - Google Analytics Help: [Identify unwanted referrals](https://support.google.com/analytics/answer/10327750), [Set up cross-domain measurement](https://support.google.com/analytics/answer/10071811). Checked October 2026. - Stripe Documentation: [Customize redirect behavior](https://docs.stripe.com/payments/checkout/custom-success-page), [After a payment link payment](https://docs.stripe.com/payment-links/post-payment). Checked October 2026. - WebKit: [Full third-party cookie blocking and more](https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/) (March 2020). MDN: [Third-party cookies](https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Third-party_cookies). Checked October 2026. - Calendly Developer: [Embed parent window events](https://developer.calendly.com/api-docs/overview/embedding/notifying-the-parent-window). Checked October 2026. ## Where Sporetag fits Sporetag treats PayPal, Stripe and other payment pages as part of your site in one tap, counts bookings made inside an embedded Calendly widget, and ties Stripe Checkout sales to the visit through the visitor id in the session's metadata. More: https://sporetag.com/docs/tracking-health --- # Leaving GA4 without losing your history > What you can take out of Google Analytics 4, what you cannot, the Data API limits, and why imported days never match a new tool's own numbers. Source: https://sporetag.com/guides/import-ga4-history By the Sporetag team. Updated October 23, 2026. You can take GA4's aggregated history with you: daily users, sessions, pages, sources, countries, devices and key events, through report downloads or the Google Analytics Data API. What you cannot take is event-level detail older than 2 or 14 months, or revenue attribution and visitor journeys, which only exist in the tool that measured them. This guide covers the three ways out, the API's quotas, why imported days never line up exactly with a new tool's own, and five rules for an honest import. ## Export before you need to Google has already shown what happens to old data. Universal Analytics stopped processing hits on July 1, 2023, and from the week of July 1, 2024, its historical data and API were gone ([Google](https://support.google.com/analytics/answer/11583528)). Anyone who had not exported lost it. GA4 is not being retired. But a property can be deleted, an account can lose its last admin, and a client can leave an agency with the login. Export the history while you have access. ## What GA4 keeps, and for how long GA4 keeps two kinds of data with different lives ([Google](https://support.google.com/analytics/answer/7667196)): - **Aggregated reports** (the standard reports, with their primary and secondary dimensions) are not cut by the retention setting. - **Event-level data,** used by explorations and funnel reports, is kept for 2 or 14 months on standard properties, and longer only on GA4 360. So the daily totals and top lists most people want are still there years later. A funnel from two years ago usually is not. ## The three ways out | Way | What you get | Good for | |---|---|---| | Download a report | A CSV or Sheet of the table on screen | One-off totals; slow for years of daily rows | | The Data API | Any report, by day, by the dimension you ask for | Daily history with sources, pages, countries and devices | | BigQuery export | Raw event rows in your own BigQuery project | Analysts who want event-level data and SQL | For moving to another tool, the Data API is the practical route: it reads the same aggregated data as the standard reports, day by day. ## The Data API's limits A standard property gets a quota of tokens: 200,000 a day and 40,000 an hour, with 10 requests at once, and 120 requests an hour that may be thresholded ([Google](https://developers.google.com/analytics/devguides/reporting/data/v1/quotas)). A report over a month of data with a breakdown can cost tens to hundreds of tokens. Two years of history with several breakdowns fits comfortably in a day, if the importer stops before the quota runs out and resumes later instead of failing. ## What will not line up, and why Imported days and new days measure different things under the same names. Expect a visible step on the day you switch, and know where it comes from: - **Users are not visitors.** A GA4 user is a browser cookie or app instance. A cookieless tool counts visitors another way, often per day. See [sessions, users and pageviews](https://sporetag.com/guides/sessions-users-pageviews). - **Sessions follow GA4's rules.** A GA4 session ends after 30 minutes of inactivity by default (the [session timeout](https://sporetag.com/glossary/session-timeout)), and a new tool may cut visits differently. - **Bounce rate was redefined.** In GA4 a bounce is a session that was not engaged: under 10 seconds, one page and no key event. Other tools use other rules. See [bounce rate in GA4](https://sporetag.com/guides/bounce-rate-ga4). - **Time is engagement time.** GA4 measures how long the page was in front, which is not how Universal Analytics or many other tools measured it. See [session duration and time on page](https://sporetag.com/guides/session-duration-time-on-page). - **Consent and blockers.** GA4 with a consent banner misses people who decline, and ad blockers stop many GA4 tags. A cookieless tool that runs without consent often shows more visits from day one. Neither is wrong; they saw different people. - **Small numbers can be hidden.** GA4 may apply [data thresholds](https://sporetag.com/glossary/data-thresholds), leaving out rows with few users when signals like demographics are on ([Google](https://support.google.com/analytics/answer/9383630)), and may [sample](https://sporetag.com/glossary/sampling) large reports. - **Time zones.** GA4 days follow the property's time zone. If the new tool uses another, days near midnight shift. ## Rules for an honest import 1. **Never count a day twice.** Import only the days before the new tool started. From the switch onward, only the new tool's own numbers should count. 2. **Mark the seam.** The chart should show where imported days end, so nobody reads the step as a change in the business. 3. **Keep goals by name.** GA4 key events can map to goals with the same event name, so last year's "purchase" lines up with this year's. 4. **Do not import what was never measured.** Revenue attribution and visitor journeys need the new tool's own data; a daily total cannot recreate them. 5. **Give the access back.** An import needs read access once. Revoke it when it ends. ## Where Sporetag fits From Sporetag's import code and help: the GA4 import is built and waits on Google's review of its read-only login (when shipped). When on, it reads totals, pages, landing pages, sources, UTM source, medium and campaign, countries, devices and key events, by day, newest first, and stops and resumes around the property's hourly and daily quota. Only days before Sporetag's first tracked day come in; the chart marks the switch, and a new import replaces the old one. The Google login is revoked when the import ends. Plausible and Fathom exports import from their CSV files today. ## Common questions ### Can I export all my historical data from GA4? You can export aggregated history, such as daily users, sessions, pages and sources, through report downloads or the Data API. Event-level data for explorations is kept only for 2 or 14 months on standard properties. ### Does GA4's data retention setting delete my reports? No. It affects explorations and funnel reports. Standard aggregated reports are not cut by it. ### Why are my numbers different after switching from GA4? The tools count users, sessions and bounces with different rules, GA4 misses people who decline consent or block it, and GA4 may hold back small numbers. Expect a step on the switch day. ### Is Universal Analytics data still available? No. Google removed access to Universal Analytics data and its API starting the week of July 1, 2024. ## Sources - Google Analytics Help: [Google Analytics 4 has replaced Universal Analytics](https://support.google.com/analytics/answer/11583528), [Data retention](https://support.google.com/analytics/answer/7667196), [About data thresholds](https://support.google.com/analytics/answer/9383630), [BigQuery Export](https://support.google.com/analytics/answer/9358801). Checked October 2026. - Google for Developers: [Data API limits and quotas](https://developers.google.com/analytics/devguides/reporting/data/v1/quotas). Checked October 2026. ## Where Sporetag fits Sporetag imports daily history from Plausible and Fathom files today, and from GA4 with a read-only Google login that ends when the import does (when shipped). More: https://sporetag.com/docs/import-history --- # Unassigned traffic in GA4: causes and fixes > GA4 labels a session Unassigned when its source and medium match no channel rule. The rules, the tag values that fall through, and how to fix a spike. Source: https://sporetag.com/guides/ga4-unassigned-traffic By the Sporetag team. Updated October 23, 2026. GA4 puts a session in the Unassigned channel when its source, medium and campaign match none of the rules in the default channel group; Google defines Unassigned as "the value Analytics uses when there are no other channel rules that match the event data" ([Google](https://support.google.com/analytics/answer/9756891)). Most Unassigned traffic comes from UTM values GA4 does not recognize, such as `utm_medium=newsletter` or `utm_medium=qr`, and the fix is to change the tags or add a custom channel group. The rest comes from events that reach GA4 without a session's source attached. This guide shows how to tell which you have, and how to fix each. ## How GA4 assigns a channel GA4 reads each session's source, medium and campaign and walks down its channel rules. The first match wins. The rules that catch most manual tags ([Google](https://support.google.com/analytics/answer/9756891)): | Channel | Matches when | |---|---| | Direct | Source is `(direct)` and medium is `(not set)` or `(none)` | | Email | Source or medium matches `email`, `e-mail`, `e_mail` or `e mail` | | Organic Social | Source is on Google's social list, or medium is `social`, `social-network`, `social-media`, `sm`, `social network` or `social media` | | Paid Social | Source is on the social list and the medium is paid: it contains `cp` (as in `cpc`), starts with `paid`, or is `ppc` or `retargeting` | | Paid Search | Source is on the search list and the medium is paid | | Paid Other | The medium is paid and the source is on no list | | Display | Medium is `display`, `banner`, `expandable`, `interstitial` or `cpm` | | Referral | Medium is `referral`, `app` or `link` | | SMS | Source or medium is exactly `sms` | | Affiliates | Medium is `affiliate` | | Audio | Medium is exactly `audio` | | Mobile Push Notifications | Medium ends with `push`, or contains `mobile` or `notification`, or source is `firebase` | | Organic Video | Source is on the video list, or medium contains `video` | | Cross-network | Campaign name contains `cross-network` | Anything that matches none of these is Unassigned. The source lists (search, social, video, shopping) are in a spreadsheet linked from the same Google page. ## Tag values that fall through | Tags on the link | GA4 channel | Why | |---|---|---| | `utm_source=newsletter&utm_medium=newsletter` | Unassigned | Neither value contains "email" | | `utm_source=klaviyo&utm_medium=email` | Email | Medium matches | | `utm_source=qr&utm_medium=qr` | Unassigned | No rule for `qr` | | `utm_source=print&utm_medium=flyer` | Unassigned | No rule for print | | `utm_source=podcast&utm_medium=podcast` | Unassigned | Only `audio` matches | | `utm_source=podcast&utm_medium=audio` | Audio | Medium matches | | `utm_source=partner&utm_medium=cpc` | Paid Other | Paid medium, source on no list | | `utm_source=instagram&utm_medium=paid-social` | Paid Social | Social source and a medium starting with "paid" | The lesson: `utm_medium` decides the channel. Pick mediums from Google's list unless you have a reason not to. See [UTM parameters](https://sporetag.com/guides/utm-parameters) for a full scheme. ## Find what is Unassigned 1. Open **Reports**, **Acquisition**, **Traffic acquisition**. 2. Change the primary dimension to **Session source / medium**. 3. Filter **Session default channel group** to exactly `Unassigned`. 4. Sort by sessions. Each row names its cause: - **A real source with an odd medium** (`mailchimp / newsletter`, `qr / qr`): a tagging fix. - **`(not set) / (not set)`** or a blank source: the session had no source when the event arrived. See the next section and [GA4 (not set)](https://sporetag.com/guides/ga4-not-set). - **A source you send from your server**, or your payment or booking domain: events sent without a session. See below. ## Events that arrive without a session GA4 ties an event to a session's source through the session's id. Two common setups break that: - **Measurement Protocol (server) events.** Events sent from your server join the browser's session only when they carry its `client_id` and `session_id`. A new `session_id` creates a new session ([Google](https://developers.google.com/analytics/devguides/collection/protocol/ga4/sending-events)), and that session has no source. Google also says events meant to join a browser session should arrive within 48 hours, or attribution may not work as expected. - **Events that fire before the Google tag.** In Tag Manager, an event tag that fires before the Google tag sends data GA4 cannot place in a session. Fire the Google tag on **Initialization - All Pages**. The [(not set) guide](https://sporetag.com/guides/ga4-not-set) covers the steps. ## Fix it **Fix the tags, going forward.** Change mediums to values GA4 knows: `email` not `newsletter`, `audio` for podcasts, `sms` for texts. Write the scheme down and use a link builder with presets, so nobody types tags by hand. **Add a custom channel group, for what you cannot retag.** Printed QR codes and old emails keep their tags forever. A custom channel group can add a "QR and print" channel that matches `qr` and `print`. A standard property can have 2 custom groups, they apply to past data, and traffic goes to the first channel whose rule it matches, so put specific channels above broad ones ([Google](https://support.google.com/analytics/answer/13051316)). **Fix server events.** Pass the browser's `client_id` and `session_id` to your server when the visitor checks out or signs up, and send them back with the event. ## Where Sporetag fits Sporetag has no channel rules: reports show the source and UTM values each visit carried, by name, so nothing falls into a bucket like Unassigned. Its link builder presets keep links on one lowercase scheme that GA4 also reads well (`email`, `sms`, `social`, `paid-social`, `cpc`), with two exceptions to know if you also run GA4: the QR code and print presets use the mediums `qr` and `print`, which GA4 puts in Unassigned. Add a custom channel group for them, as above. ## Common questions ### What does Unassigned mean in GA4? The session's source, medium and campaign matched none of GA4's channel rules. It is not lost or broken traffic; GA4 just could not name its channel. ### Why did my Unassigned traffic suddenly spike? Usually a new campaign or email went out with mediums GA4 does not recognize, or a new server-side or Tag Manager setup started sending events without a session. Break Unassigned down by session source / medium for the day of the spike. ### Is Unassigned the same as Direct? No. Direct is traffic with no source at all. Unassigned has a source or medium, just not one any channel rule matches. ### Can I move old Unassigned traffic into the right channel? Yes, with a custom channel group. It applies to past data, so a rule that matches `qr` re-labels old QR code sessions too. ## Sources - Google Analytics Help: [Default channel group](https://support.google.com/analytics/answer/9756891), [Custom channel groups](https://support.google.com/analytics/answer/13051316). Checked October 2026. - Google for Developers: [Send Measurement Protocol events](https://developers.google.com/analytics/devguides/collection/protocol/ga4/sending-events). Checked October 2026. ## Where Sporetag fits Sporetag reports the source and UTM values a visit carried, by name, with no channel rules to fall through, and its link builder presets keep every link on one lowercase scheme. More: https://sporetag.com/docs/utm-presets --- # UTM parameters: the complete guide, with a naming scheme that holds up > What each UTM parameter does, the naming rules GA4 actually applies, a scheme for source, medium and campaign, and the mistakes that break your reports. Source: https://sporetag.com/guides/utm-parameters By the Sporetag team. Updated October 23, 2026. UTM parameters are tags you add to the end of a link so your analytics knows where a visit came from. They are the most reliable source signal you control: a referrer can be dropped by an app or a browser, but tags written into the link arrive with the visit. This guide covers what each parameter does, a naming scheme that keeps reports clean, and the mistakes that quietly ruin them. ## The parameters | Parameter | Answers | Example | |---|---|---| | `utm_source` | Who sent the visit | `instagram`, `google`, `newsletter` | | `utm_medium` | What kind of channel | `social`, `cpc`, `email`, `sms`, `qr` | | `utm_campaign` | Which push or offer | `spring-sale`, `webinar-oct` | | `utm_content` | Which link, creative or placement | `bio`, `story`, `video-a` | | `utm_term` | Which keyword or audience | `running-shoes`, `lookalike-1` | | `utm_id` | A campaign id, for joining cost data | `cmp-1042` | Google says to always use `utm_source`, `utm_medium` and `utm_campaign`, and GA4 also reads `utm_id`, `utm_source_platform`, `utm_creative_format` and `utm_marketing_tactic` ([Google](https://support.google.com/analytics/answer/10917952)). Google notes the last two are not currently reported in GA4. Any parameter you leave out shows as `(not set)`. The names come from Urchin, the analytics company Google bought in 2005 that became Google Analytics. Every major analytics tool reads them now, including Sporetag, Plausible, Matomo and Shopify. ## Source and medium do different jobs The most common mistake is putting the same idea in both. - **Source** is the specific site, app or list: `facebook`, `instagram`, `google`, `bing`, `newsletter`, `partner-name`. - **Medium** is the kind of channel: `social`, `paid-social`, `cpc`, `email`, `sms`, `qr`, `print`, `referral`. `utm_source=facebook&utm_medium=facebook` tells you nothing the source did not. `utm_source=facebook&utm_medium=paid-social` tells you it was a paid Facebook ad, not a post. ## The medium decides the channel in GA4 GA4 sorts each visit into a channel, such as Paid Social or Email, by rules on source and medium ([Google](https://support.google.com/analytics/answer/9756891)). Your medium values have to match those rules, or visits fall into "Unassigned": - **Email** matches a source or medium of `email`, `e-mail`, `e_mail` or `e mail`. - **Organic Social** matches a known social source, or a medium of `social`, `social-network`, `social-media`, `sm`, `social network` or `social media`. - **Paid Social** needs a known social source and a medium matching `^(.*cp.*|ppc|retargeting|paid.*)$`: `cpc`, `ppc`, `paid-social` and `paid_social` all work. - **Referral** matches a medium of `referral`, `app` or `link`. So `utm_medium=newsletter` does not land in Email, and `utm_medium=ig` does not land in Social. Pick the values the rules expect. Channel rules are not case sensitive, but parameter values are, which is the next point. ## Case matters GA4 treats `utm_source=Google` and `utm_source=google` as two different sources ([Google](https://support.google.com/analytics/answer/10917952)). One teammate typing `Facebook` and another typing `facebook` splits the same channel into two rows. Pick one rule and enforce it. The simplest: - lowercase everything, - hyphens between words, no spaces, - no dates in `utm_source` or `utm_medium`, only in `utm_campaign` if you need them. ## A naming scheme you can copy | Where the link goes | utm_source | utm_medium | utm_content | |---|---|---|---| | Instagram bio | `instagram` | `social` | `bio` | | Instagram story | `instagram` | `social` | `story` | | TikTok bio | `tiktok` | `social` | `bio` | | Meta ads | `facebook` | `paid-social` | the ad name | | Google Ads | `google` | `cpc` | the ad | | Email newsletter | `newsletter` | `email` | the link or button | | SMS | `sms` | `sms` | the message | | QR code on print | `qr` | `qr` | where it was printed | `utm_campaign` carries the push itself: `spring-sale`, `black-friday-2026`, `webinar-oct`. Keep a shared list of campaign names, so the same campaign has one spelling everywhere. These are the presets in Sporetag's [UTM builder](https://sporetag.com/tools/utm-builder) and link form, so links made there follow the scheme automatically. ## Let ad platforms fill in the names Typing ad names into tags by hand drifts out of date the moment someone renames an ad. Ad platforms can fill them in for you with dynamic values in the URL parameters field: - **Meta:** `utm_campaign={{campaign.name}}&utm_content={{ad.name}}&utm_term={{adset.name}}` - **Google Ads:** auto-tagging adds `gclid` on its own, and ValueTrack values such as `{campaignid}` and `{keyword}` work in a tracking template. - **TikTok:** `__CAMPAIGN_NAME__`, `__AID_NAME__` and `__CID_NAME__`. Check each platform's current help page before relying on these: the names change from time to time. The [click ids guide](https://sporetag.com/guides/click-ids-explained) covers `gclid`, `fbclid` and the others. ## Six mistakes that break reports 1. **Tagging internal links.** A UTM tag on a link from your own home page to your shop replaces the real source of that visit. In GA4, later key events are credited to your own tag instead of the ad or post that brought the visitor. In Sporetag, a tagged link always starts a visit with its tag. Never tag links between your own pages. 2. **Mixed case.** `Email` and `email` become two rows that never add up. 3. **Medium values GA4 does not recognize.** `newsletter`, `ig`, `fb-ads` and `paid` fall outside the channel rules or land in the wrong channel. 4. **Redirects that drop the query string.** Test each landing page: open it with `?utm_source=test` and check the tag is still in the address bar after every redirect. 5. **Personal data in tags.** Never put an email address or a name in a UTM value. It ends up in analytics reports and in the history of everyone who shares the link. 6. **Long, ugly links in public places.** People trim them, and a trimmed link loses its tags. Use a short link for bios, print, SMS and anything spoken aloud. ## Short links and UTM tags work together A [short link](https://sporetag.com/glossary/short-link) such as `go.yourbrand.com/spring` keeps the tags out of sight. It counts the click itself, then forwards to the full tagged address. That gives you two records: the click, even if the visit is never counted, and the tagged visit on your site. It is the most reliable way to track a bio link, a QR code or a text message. See [how to track an Instagram link in bio](https://sporetag.com/guides/track-instagram-link-in-bio) and [how to track SMS link clicks](https://sporetag.com/guides/track-sms-link-clicks). ## Common questions ### Are UTM parameters bad for SEO? No, as long as you only use them on links from other places to your site. Your pages should carry a canonical tag pointing to the address without the tags, so search engines index one version. ### Are UTM parameters case sensitive? Yes. In GA4, `Google` and `google` are separate values. GA4's channel rules ignore case, but your source, medium and campaign reports do not. ### Do I need UTM tags on Google Ads links? Not for GA4 if auto-tagging is on, since GA4 reads the `gclid`. Many teams add them anyway, so other tools that cannot read Google's click data still see the campaign. ### What is the difference between utm_content and utm_term? `utm_term` was made for the paid keyword. `utm_content` tells apart links or creatives in the same campaign. Many teams use `utm_term` for the ad set or audience on social ads, which is fine if everyone does it the same way. ### Can UTM parameters track conversions? They tell analytics where a visit came from. The conversion is counted by your analytics or store, and credited to that source by its attribution rule. ## Sources - Google Analytics Help: [URL builders: collect campaign data with custom URLs](https://support.google.com/analytics/answer/10917952), [Default channel group](https://support.google.com/analytics/answer/9756891). Checked October 2026. - Ad platform dynamic values were checked against each platform's help pages in October 2026. ## Where Sporetag fits Sporetag's free UTM builder and its short links use platform presets (Instagram bio, SMS, email, QR, Meta and Google ads), so every link follows one lowercase scheme without anyone remembering it. More: https://sporetag.com/tools/utm-builder --- # How to track your Instagram link in bio, through to the sale > Instagram's own insights stop at link taps. How to see which bio link, story or post brought visits, signups and sales, with tags and a short link. Source: https://sporetag.com/guides/track-instagram-link-in-bio By the Sporetag team. Updated October 23, 2026. Instagram tells a professional account how many people tapped the link in its bio. It does not tell you what they did next: whether they bought, which product page they landed on, or whether last Tuesday's reel sent more buyers than the story you posted on Friday. To get from "taps" to "sales", the visit has to arrive at your site with its source attached. This guide shows how, from the simplest version to the one that holds up across stories, posts and several links. ## Why bio traffic gets lost When someone taps a link on Instagram, the link opens in Instagram's own in-app browser. Depending on the app version and the phone, the visit may arrive with a referrer such as `l.instagram.com`, or with none at all. A visit with no referrer and no tags is counted as [direct traffic](https://sporetag.com/guides/direct-traffic-explained). For accounts that rely on Instagram, this is often the single biggest leak in their reports. There is a second gap. Many buyers tap the bio link, look around, leave, and come back later by typing your name or searching for it. Unless your analytics remembers the first visit, the sale goes to search or direct. ## Step 1: tag the link Put [UTM parameters](https://sporetag.com/guides/utm-parameters) on the link in your bio. A good set: ```text https://yourshop.com/?utm_source=instagram&utm_medium=social&utm_content=bio ``` - `utm_source=instagram` names the app. - `utm_medium=social` puts it in GA4's Organic Social channel ([Google](https://support.google.com/analytics/answer/9756891)). - `utm_content=bio` tells it apart from story and post links. Add `utm_campaign` when the link points to a specific push, such as `utm_campaign=spring-drop`. Change it when the push changes. ## Step 2: use a short link instead of the long one A tagged link works, but it has three problems in a bio: it looks messy, it is easy to break when you edit it on a phone, and Instagram's link taps cannot be compared with visits, because they are counted in two different tools. A [short link](https://sporetag.com/glossary/short-link) on your own domain, such as `go.yourbrand.com/ig`, fixes all three: - It counts each tap itself, before the visit, so you see taps and visits side by side. - It forwards to the full tagged address, so the visit still carries its source. - You can change where it points without editing your bio. Make one short link per place: one for the bio, one for stories, one per campaign. The tags tell them apart in reports. Using a link page such as Linktree instead? Tag each of its buttons; see [how to track Linktree clicks](https://sporetag.com/track/linktree). ## Step 3: give stories and posts their own links Story link stickers and links in reel captions or comments are separate traffic. Give each its own short link, with `utm_content=story` or the post's name, so you can compare them. If you use a link-in-bio page with many buttons, give each button its own tagged link too, or every visit will look like it came from the link-in-bio tool. ## Step 4: count the result, not just the visit A visit is not a sale. Decide what counts, then set it up as a goal or [key event](https://sporetag.com/glossary/key-event): - **A store:** the purchase. Read it from your store, not only from a browser tag on the thank-you page, because checkout pages often do not run your tags. - **A service business:** the booking, the form or the call tap. - **A creator:** the signup, the sponsor click or the product sale. Then read your report by `utm_content`: bio against story against post, by sales, not by taps. ## Step 5: keep the source for buyers who come back A visitor who taps on Monday and buys on Thursday after searching your name needs something to connect the two visits. You have three options: - **Accept last click.** Simple, and the bio gets credit only for same-visit sales. - **Use a tool with a first-party id**, kept on your own domain, so the Monday source is remembered. Safari caps cookies set by script at 7 days ([WebKit](https://webkit.org/blog/8613/intelligent-tracking-prevention-2-1/)), so this works best for buyers who return within a week. In the EU and UK it usually needs consent. - **Ask for an email early.** A signup or discount form ties later purchases to the person, whatever device they buy on. ## What Instagram's own numbers can and cannot tell you | Question | Instagram insights | Your analytics with tagged links | |---|---|---| | How many people tapped the bio link? | Yes | Yes, with a short link | | Which page did they land on? | No | Yes | | Did they buy or sign up? | No | Yes | | Which post or story drove the sale? | No | Yes, with one link per post or story | | Who saw the post but did not tap? | Yes, as reach | No | Use both. Instagram for reach and engagement, your analytics for what happened after the tap. ## Common questions ### Can I see who clicked my Instagram link? No tool shows you the people, and you should be wary of any that claims to. You can see how many tapped, when, from which country and device, and what they did on your site. ### Why do my link taps not match website visits? Taps happen in Instagram. Visits are counted by your analytics once the page loads and the tag runs. People close the page before it loads, ad blockers stop tags, and some taps are repeats. A short link counts taps on its own, so you can see where the drop happens. ### Do link-in-bio tools track sales? Most count clicks on their buttons. Few can see what happens on your site after the click. Tag each button's link so your own analytics can. ### Will UTM tags hurt how my link looks? Only if you paste the long link. A short link on your own domain hides the tags and stays readable. ## Sources - Google Analytics Help: [Default channel group](https://support.google.com/analytics/answer/9756891). Checked October 2026. - Instagram Help Center: [Add a website to your Instagram profile](https://help.instagram.com/362497417173378). Checked October 2026. - WebKit: [Intelligent Tracking Prevention 2.1](https://webkit.org/blog/8613/intelligent-tracking-prevention-2-1/). ## Where Sporetag fits A Sporetag short link with the Instagram bio preset counts every tap, tags the visit, and when it points to a site you track, ties later signups and sales that day back to the link. More: https://sporetag.com/platforms/instagram --- # gclid, fbclid and other click ids, explained > What gclid, gbraid, wbraid, fbclid, ttclid and msclkid are, what each one is for, how long they last, and why keeping them matters for ad tracking. Source: https://sporetag.com/guides/click-ids-explained By the Sporetag team. Updated October 23, 2026. When someone clicks an ad, the ad platform adds a long random value to the link: `gclid=` for Google, `fbclid=` for Meta, `ttclid=` for TikTok. These are click ids. They let the platform match a later sale back to the exact click, which is how the platform learns which ads work. UTM tags tell your analytics where a visit came from. Click ids tell the ad platform which of its clicks turned into a sale. You usually want both. ## The click ids, by platform | Parameter | Platform | Added by | |---|---|---| | `gclid` | Google Ads | Auto-tagging, on by default in most accounts | | `gbraid` | Google Ads | iOS traffic where `gclid` cannot be used, for app conversions | | `wbraid` | Google Ads | iOS traffic where `gclid` cannot be used, for web conversions | | `fbclid` | Meta (Facebook, Instagram) | Outbound links from Meta's apps and sites | | `ttclid` | TikTok | TikTok ads, when click id tracking is on ([TikTok attribution](https://sporetag.com/guides/tiktok-ads-attribution)) | | `msclkid` | Microsoft Advertising | Auto-tagging | | `li_fat_id` | LinkedIn | LinkedIn ads | | `ScCid` | Snapchat | Snapchat ads | | `epik` | Pinterest | Pinterest ads | | `twclid` | X | X ads | | `rdt_cid` | Reddit | Reddit ads | Google introduced `gbraid` and `wbraid` for iOS 14 and later, where Apple's rules limit the use of `gclid` without consent. They are aggregate identifiers, so they cannot tie a conversion to one person ([Google](https://support.google.com/google-ads/answer/10417364)). ## What a click id is for A click id does nothing on its own. It is a key. The ad platform keeps a record of the click under that key: the campaign, ad set, ad, time and placement. Later, when you report a conversion with the same key, the platform can say exactly which ad earned it. There are three ways the key comes back to the platform: 1. **The platform's own tag** on your site reads it from the address and stores it in a first-party cookie, then sends it with the conversion. Meta's pixel stores it as `_fbc`; Google's tag stores the `gclid` in its own cookies. 2. **Your server** keeps it with the order and sends it through the platform's server API: the Meta Conversions API, or Google Ads offline conversion upload. 3. **A file upload** of conversions with their click ids, for sales that happen offline, such as a phone order. For Meta, the server form is called `fbc`, built as `fb.1.