VisualQ

Piano Analytics

Verify analytics tracking server-side — compare what the browser fires with what Piano actually ingests.

Business plan

The Piano Analytics integration adds a third source of truth to VisualQ's tracking-test pillar. After the browser-side audit verifies the dataLayer, VisualQ asynchronously queries Piano's Data API and produces a 3-way comparison: plan ↔ browser ↔ Piano.

This catches a category of issues nothing else surfaces:

  • Hits dropped by ad-blockers or browser tracking-protection
  • Events lost to client-side ITP / sampling
  • Wrong site_id on a staging/prod environment swap
  • Schema-validation rejections in Piano's ingestion pipeline
  • Variables that look correct in the browser but never reach the server

Prerequisites

  • A Piano Analytics account (S3 or S4 region)
  • An API access key + secret with data:read scope
  • The site ID of the Piano site you want to verify against

Setup

1. Generate Piano API credentials

  1. In Piano, open User profile › API keys
  2. Click Create new key
  3. Grant the data:read scope (Data Query API)
  4. Copy both the Access key and the Secret key

2. Configure in VisualQ

  1. Open Settings › Integrations on a project
  2. Click Connect on the Piano Analytics card
  3. Enter:
    • Site ID — the numeric Piano site identifier
    • Access key + Secret key — from step 1
    • RegionS3 (default) or S4 (EU instance)
  4. Click Save

3. Test the credentials

Re-open the integration and click Test. VisualQ will fire a minimal getData request to confirm the keys can read your site. The test does not consume any quota beyond a single API call.

Secrets are encrypted at rest and never returned to the browser. The Settings UI shows masked values (••••••••) on subsequent loads.

How it works

flowchart LR
  A[Run tracking-test] --> B[Worker captures<br/>browser dataLayer<br/>+ Piano cookies]
  B --> C[/api/worker/callback]
  C --> D[Save audit doc<br/>pianoSummary: pending]
  C --> E[Schedule Inngest<br/>tracking/piano.verify]
  E -.->|10 min sleep| F[Query Piano Data API]
  F --> G{Hits found via<br/>visitor_id?}
  G -->|Yes — high confidence| H[Merge 3-way verdict]
  G -->|No — fallback| I[Query by URL +<br/>time window]
  I -->|Low confidence| H
  H --> J[Persist + SSE update UI]

Phase 1 — Browser-side audit (synchronous)

When you run a tracking-test, the worker captures the dataLayer and Piano visitor ID cookies (_pcid, atuserid, idrxvr, …) from the browser context after each navigation. These cookies, plus the run start and end timestamps, are sent back to VisualQ along with the usual audit report.

Phase 2 — Piano-side verification (asynchronous, ~10 min later)

Piano's Data API has a 5–30 minute ingestion latency. VisualQ schedules an Inngest job that:

  1. Sleeps 10 minutes (covers ~95% of cases)
  2. Queries Piano's getData endpoint with filter: { user_id: { $in: [<captured visitor IDs>] } }high-confidence matching
  3. If no rows come back, falls back to filter: { page_url: { $in: [<URLs>] } } over the run's time window — low-confidence matching (may include real-user traffic)
  4. For every plan variable, resolves the corresponding Piano column (analyticsDimension x4, analyticsMapping page_chapter1, or the raw variable name) and produces a 3-way verdict

The 3-way verdict matrix

BrowserPianoVerdict
Value matchesSame valuepass — fully verified end-to-end
Value matchesDifferent valuefail — Piano received a different value
Value matchesAbsentmissing — hit lost in transit (ad-blocker, ITP, …)
Absent (mandatory)Absentfail — both sides missing a required variable
Absent (optional)Absentpass — correctly absent on both sides
not_setHas valuefail — Piano received an unexpected value
not_setAbsentpass — confirmed absent server-side

What you see in the UI

The tracking audit report grows two extra elements when Piano is enabled:

  • A Piano Analytics section in the audit summary card (status: pending → completed/failed) with pass/fail/missing tallies
  • A Piano column on every variable row, showing the actual value Piano received and a status icon (✓, ✗, ⚠ missing, ⏱ pending)

Low-confidence banner

When VisualQ fell back to URL + time-window matching (no Piano cookies were captured — typically because the test browser blocked them or your site doesn't load the Piano SDK), an amber banner is shown:

Low-confidence matching Piano hits were matched by URL + time window because no Piano visitor IDs were captured. Results may include real-user traffic during the test window.

To get high-confidence matching, make sure your test environment runs the Piano SDK and accepts the consent banner (or runs in a consent-given state).

Zero configuration on the Piano side

Unlike most analytics QA tools, VisualQ requires no changes to your Piano configuration. We don't ask you to create a custom property, mark hits with a synthetic flag, or expose a separate site for testing. The hybrid identification strategy (visitor cookies → URL + time window) is designed to work against your existing production or staging setup as-is.

Privacy & quota

  • Secrets are encrypted at rest in Firestore using the same envelope-encryption scheme as Jira/GitLab tokens
  • API calls per run = 1 to 2 (primary + optional fallback)
  • No PII is exfiltrated; Piano data flows from Piano → VisualQ only, never the other way
  • Quota usage is minimal — Piano's getData quota is per-call, and each tracking-test costs at most 2 calls

Troubleshooting

"Piano verification pending" never resolves

  • Confirm the integration is enabled (Settings › Integrations)
  • Check the Inngest dashboard for the tracking-piano-verify function; it should fire ~10 minutes after the run completes
  • Verify the WORKER_SECRET and Piano credentials are valid (run Test)

Every variable is "missing"

  • The site you queried is probably not the one your test hit. Check the Site ID and your environment URLs.
  • Your site may not load the Piano SDK in the test environment (e.g. consent not granted). Either accept consent in your scenarios, or expect low-confidence (URL + time window) matching.

Low-confidence banner on every run

  • Confirm the Piano SDK loads on the tested URLs
  • Check that the Playwright worker isn't blocking third-party cookies
  • Cookies VisualQ looks for: _pcid, atuserid, idrxvr, atid, atauthority

Differences with browser-side tracking QA

AspectBrowser-side auditPiano integration
What's verifieddataLayer / window varsHits ingested by Piano
LatencySynchronous~10 minutes (Piano ingestion)
Catches ad-blocker drops?NoYes
Catches schema rejection?NoYes
Catches wrong site_id?NoYes
Catches dataLayer typos?YesPartially

The two layers are complementary — keep both enabled for the strongest guarantees.

On this page