Skip to content

Your privacy, your choice.

Optional technologies help us improve our services and let our partner Leadpipe identify visitors (name, business email, phone, company) so our sales team can follow up. Choose whether to allow them.

Manage preferencesPrivacy policy

Powered by Ashfort Intelligence.

Documentation

The Ashfort Intelligence pixel

A small (~4 KB gzipped), asynchronous script that records page views and the events you choose, so Ashfort Intelligence can show company-level interest. It never blocks rendering, never reads form fields, and ships no secrets to the browser.

Install

Create a website in the dashboard, add the domains allowed to send data, then copy the snippet from its setup screen — it contains your real site ID and this deployment's script host. Paste it inside <head> on every page:

html
<script async src="https://ashfortintelligence.com/pixel.js" data-site-id="YOUR_SITE_ID"></script>

To call the API before the script finishes loading, add the optional one-line queue stub first: window.ashfort=window.ashfort||function(){(ashfort.q=ashfort.q||[]).push(arguments)};

Script attributes

  • data-site-id (required) — public site ID from the setup screen (af_…).
  • data-consent — required (wait for ashfort("consent","granted")) or gcm (follow Google Consent Mode). Omit when your review concludes consent isn't needed. Must match the website's setting — the server enforces it.
  • data-endpoint — collector URL, only needed when the script is served from a different host than the app (e.g. a CDN).
  • data-storage="none" — never write to localStorage/sessionStorage; IDs live only for the page view (repeat-visit signals are lost).
  • data-spa="false" — disable automatic route-change tracking. data-auto-pageview="false" — send page views manually with ashfort("page").
  • data-debug — log what the pixel does to the console.

Custom events

Use events for actions that signal buying intent. Names are 1–64 characters of letters, numbers and _ . : -. Up to 20 flat properties (string, number, boolean) are kept; keys or values that look like personal, credential or payment data are dropped on both the client and the server.

javascript
// Track a custom event (name: letters, numbers, _ . : -)
ashfort("track", "demo_request", { plan: "growth" });
ashfort("track", "pricing_interest");

// No-code: add data attributes to any button, link or form
<button data-ashfort-event="demo_request" data-ashfort-prop-plan="growth">Book a demo</button>
<form data-ashfort-event="contact_sales">…</form>   <!-- field values are never read -->

// Consent (for data-consent="required")
ashfort("consent", "granted");   // or "denied" — clears the pixel's storage

Event names listed under Settings → Scoring (defaults: demo_request, contact_sales, trial_signup, pricing_interest, plan_selected) feed the intent score.

With data-consent="required", events are held in memory — nothing is sent and nothing is stored — until you grant consent. Wire it to your consent banner:

consent
<script async src="https://ashfortintelligence.com/pixel.js" data-site-id="YOUR_SITE_ID" data-consent="required"></script>

<script>
  // OneTrust: "C0002" = performance/analytics category
  function OptanonWrapper() {
    var ok = (window.OnetrustActiveGroups || "").indexOf("C0002") > -1;
    ashfort("consent", ok ? "granted" : "denied");
  }
  // Cookiebot
  window.addEventListener("CookiebotOnConsentReady", function () {
    ashfort("consent", Cookiebot.consent.statistics ? "granted" : "denied");
  });
</script>
  • Call ashfort("consent", …) on every page load — the pixel does not persist consent itself.
  • "denied" clears the pixel's storage and drops queued events.
  • data-consent="gcm" reads analytics_storage from Google Consent Mode v2 (gtag("consent", …) / your CMP's GCM integration). If any region-scoped default denies analytics_storage, the pixel can't tell whether the visitor is in that region, so it waits for a consent update instead of following a general "granted" default.
  • Global Privacy Control and Do Not Track are always treated as opt-outs.

Single-page apps

The pixel listens to history.pushState, replaceState and popstate, and records a page view when the path changes (query-only changes are ignored). Works with React Router, Next.js, Vue Router, SvelteKit and similar.

First-party identify (optional)

If people sign in to your site or app, you may attach activity to someone already known to you — only with a lawful basis, a matching privacy notice, and after enabling Accept first-party identify calls on the website. It is disabled by default and rejected by the server otherwise.

javascript
ashfort("identify", {
  id: "user_8412",              // your stable user id (required)
  companyDomain: "acme.com",    // optional; else derived from a business email
  email: "ana@acme.com",        // optional
  name: "Ana Ortiz",            // optional
  phone: "+44 20 7946 0000",    // optional
  lawfulBasis: "contract"       // consent | contract | legitimate_interests
});

Ashfort Intelligence never infers identity from anonymous traffic and never enriches people with third-party profile data.

Known contacts & the Contacts API

Ashfort Intelligence distinguishes anonymous visits (at most matched to a company by a configured enrichment provider) from known contacts — people your organization already knows. A person's name, email or phone only ever comes from a source you control, and every contact is labelled with that source:

  • Website identify — ashfort("identify", …) on a site where you enabled it (above).
  • Contacts API — your backend sends people who submitted one of your consented forms. The pixel never reads form fields.
  • Added by your team — entered in the dashboard with a lawful basis.

Create a key under Settings → API keys (server-side only; calls from a browser are refused):

shell
curl -X POST https://YOUR_APP_HOST/api/v1/contacts \
  -H "Authorization: Bearer $ASHFORT_API_KEY" -H "Content-Type: application/json" \
  -d '{"externalId":"form-123","name":"Ana Ortiz","email":"ana@acme.com",
       "lawfulBasis":"consent","consentedAt":"2026-09-23T10:15:00Z",
       "sourceDetail":"Demo request form","visitorId":"<from ashfort.getVisitorId()>"}'

curl -X DELETE https://YOUR_APP_HOST/api/v1/contacts/form-123 -H "Authorization: Bearer $ASHFORT_API_KEY"

lawfulBasis is required. To connect a submission to earlier visits, read ashfort.getVisitorId() in the page (it returns null until consent allows storage) and send it along with your form to your backend. Deleting a contact also deletes the activity linked to it.

Optional fields, all supplied by you and shown with their source on Raw traffic: jobTitle and employer; doNotContact (once true, later calls can't clear it); and marketingOptIn — send true only when the person opted in to marketing (accepting your terms is not an opt-in). With self-reported demographics enabled with a stated purpose under Settings → Privacy & data, you may also send ageRange and gender as the person reported them; they are shown only in aggregate. Anything else — income, net worth, homeownership, marital or family status, personal phones, home addresses — is ignored and listed back as ignoredFields.

Raw traffic & CSV export

Raw traffic (in the sidebar and the header) lists every event the collector actually received for your organization, one row per event, newest first, with search, filters and a CSV export of the filtered rows. It is an audit view: every cell is filled only from an authorized source, and a dash means nothing was supplied.

ColumnFilled from
Received, event, page, referrer, campaign, websiteThe pixel
Company, domain, match provider · confidence · timeA configured enrichment provider, a business domain you supplied, or an authorized identity provider's employer — recorded per visit
Name, business email, business phone, employer, job title, person sourceOnly a known contact from an authorized source (your identify calls, the Contacts API, your team, or a licensed identity provider you contracted and authorized); each field shows its own source
Age range, genderNever per person. Shown only as aggregates on Overview when self-reported demographics are enabled with a stated purpose
NetworkCoarse country from your hosting provider's header; device and browser from the user agent. No city or address is derived from an IP

Exports use the same filters, include a *_source column for every person field plus do_not_contact and marketing_opt_in, are capped at 50,000 rows, neutralise spreadsheet formulas and are written to the organization's audit log. The export endpoint requires a signed-in member of the organization; there is no API-key access to it.

Traffic sources & geography

Each session is attributed to a channel from its landing page view: UTM medium first (paid, email, social), then the referrer (organic search, social, email, other referral), otherwise Direct. Tag campaigns with standard utm_* parameters; they are the only query parameters the pixel keeps.

Geography is country level only. It comes from your hosting provider's header (Vercel x-vercel-ip-country, Cloudflare cf-ipcountry) or, when the operator configures one, a local MaxMind GeoLite2 Country database. City and coordinates are never stored, and country storage can be switched off per organization.

Age & gender

Ashfort Intelligence does not infer a visitor's age or gender, and does not buy it from data brokers. Two opt-in sources can populate the aggregate Audience demographics panel:

  • Google Analytics 4: connect your property under Settings → Integrations. Google provides age brackets and gender only with Google Signals enabled, anonymised and thresholded.
  • Self-reported: if people give you an age range or gender themselves (for example on a consented form), and you enable it under Settings → Privacy & data, send it with identify:
javascript
ashfort("identify", {
  id: "user_8412",
  ageRange: "25-34",   // or a whole-number age; stored only as a range, under-18 discarded
  gender: "female"     // female | male | non_binary | other | prefer_not_to_say
});

Values are never shown for an individual. Charts need at least 10 people in the selected range and hide any group smaller than 5. Custom event properties named like age or gender are always dropped.

Household and personal attributes — income, net worth, homeownership, marital or family status, personal phone numbers and home addresses — are not accepted as lead fields and are never inferred. Identity providers can't supply age or gender either.

Identity resolution (licensed providers)

A pixel records activity; on its own it never reveals who someone is. If your organization contracts a licensed identity-resolution provider, an admin can add it under Settings → Integrations — with the contract reference and date, the intended use, the lawful basis and an attestation that the contract authorizes matching your website visitors for that use. Then switch it on per website. Test traffic is never sent, each browser is looked up at most once a day, and the pixel sends nothing for visitors with Global Privacy Control or without required consent.

Your provider (or a small middleware) implements this contract:

http
POST <your endpoint>
Authorization: Bearer <provider API key>

{ "requestId": "…", "ip": "198.51.100.23", "userAgent": "…",
  "page": { "host": "www.example.com", "path": "/pricing" },
  "occurredAt": "2026-09-23T14:05:00Z", "intendedUse": "<your stated use>" }

→ { "matched": true, "confidence": 0.86, "reference": "…",
    "person": { "name": "…", "businessEmail": "…", "businessPhone": "…",
                "jobTitle": "…", "employer": { "name": "…", "domain": "…" } } }

Only those business fields are kept (free-mail addresses aren't business email); anything else is discarded and counted. Matches below your minimum confidence are discarded. Errors and timeouts are logged and shown; nothing is created. Match rate, field coverage, fields per match and latency are shown only from at least 20 of your own lookups, with the method.

Disclosures & permissions

Settings → Privacy & data generates notice text from your live configuration — what the pixel collects, why, which providers receive it, retention, and how visitors exercise their choices. Each website can also publish a public /disclosure/<site id> page to link from your privacy notice. Keep acceptance of your terms separate from tracking permission and marketing opt-ins; a website visit is never permission to contact someone.

AI intelligence

The AI intelligence panel on Overview summarises the selected range and traffic view: visitors, sessions, matched companies, top accounts and signals, channels, pages and pipeline. It is generated from aggregates and company-level facts only — no visitor IDs, contact details or per-person traits are ever sent to a model.

  • Rule-based insights are always available and restate the numbers on the page.
  • When the operator sets ANTHROPIC_API_KEY, Claude (INSIGHTS_MODEL, default claude-opus-5) writes the summary from the same aggregates, with a structured output schema and instructions not to invent figures, identify people or promise uplift. Without a key the panel is labelled AI not configured.
  • Results are cached per organization, range and view for six hours; Refresh regenerates on demand (20 per hour per organization, audit-logged). The footer shows when it was generated and how many events it covers.
  • With no events in the view, the panel shows setup guidance instead of insights.

Testing & debugging

  • Sandbox: on the website setup screen, “Open sandbox test” loads the real script with a signed one-hour token and shows the collector's responses.
  • Live site: open any page with ?ashfort_test=1. The pixel sends a page view and a pixel_test event flagged as test and logs the server's reply in the console. The setup screen updates within seconds.
  • Debug logging: add ?ashfort_debug=1 or the data-debug attribute.
  • Common errors: origin_not_allowed (add the domain to the website), consent_required (grant consent or change the site's consent mode), site_paused, monthly_limit_reached.

CMS & tag managers

  • Google Tag Manager: Custom HTML tag on All Pages; set “Additional consent checks” to analytics_storage if you use Consent Mode. The setup screen generates a GTM-safe loader.
  • WordPress: a header-code plugin (e.g. WPCode) or a wp_head hook in a child theme.
  • Shopify: layout/theme.liquid before </head>; optionally forward the Customer Privacy API decision to ashfort("consent", …).
  • Webflow: Site settings → Custom code → Head code.
  • Squarespace: Settings → Advanced → Code Injection → Header. Wix: Settings → Custom code → Head, all pages.
  • Ad blockers may block third-party analytics hosts. Serving the script and collector from your own subdomain via a reverse proxy (set PIXEL_SCRIPT_URL/COLLECT_URL) is supported; it does not bypass consent — the same rules apply.

Data collected

  • Page path with query strings removed (except UTM tags) and ID-, token- and email-like segments redacted.
  • External referrer (origin + path), UTM campaign tags.
  • Random first-party visitor ID (localStorage _ashfort_vid) and session ID (sessionStorage _ashfort_sid, 30-minute inactivity).
  • Device type and browser family (the full user agent is not stored), optional two-letter country from your CDN.
  • The request IP is used in memory to look up a company through a configured, licensed provider and is never stored; lookups are cached against a keyed hash.

Never collected: form values, passwords, payment details, page content, keystrokes, sensitive traits. Retention is configurable per organization; see privacy.

Intent scoring

Each account's score is the sum of these signals (count × weight, capped), clamped to 100. Weights, caps, paths and event names are adjustable per organization. Defaults:

SignalWeightCap
Page views — Every page view from the account.115
Repeat visits — Each session after the first.618
High-value pages — Views of paths you mark as buying research.520
Pricing interest — Pricing page views or pricing events.1020
Demo / sales requests — Custom events you map to demo or contact requests.3030
Multiple visitors — Each additional anonymous browser from the same account.515
Recent activity — Active within the recency window.1010

Accounts at or above the threshold (default 50) are marked qualified and suggested as leads.

Security model

  • The site ID is public by design. The collector validates it, checks the request Origin against the website's allowed domains, enforces the consent mode, rate-limits per IP and per site, validates and size-limits payloads, and filters bots and automation.
  • Origin checks stop other websites from sending data from visitors' browsers; like any public analytics endpoint, they cannot stop a determined non-browser client from sending fabricated events, which is why rate limits and plan limits also apply.
  • Responses contain no tenant data. Dashboard and API access is session-based with server-side tenant checks on every read and write.

Privacy preferences

Choose which technologies Ashfort Intelligence may use on this website. You can change this at any time.

Powered by Ashfort Intelligence.Privacy policy