Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion src/__tests__/funnel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
* worth more than any metric.
*/

const beaconMock = vi.fn((_url: string, _body: unknown) => true);

Check warning on line 16 in src/__tests__/funnel.test.ts

View workflow job for this annotation

GitHub Actions / check

'_body' is defined but never used

Check warning on line 16 in src/__tests__/funnel.test.ts

View workflow job for this annotation

GitHub Actions / check

'_url' is defined but never used

beforeEach(() => {
trackMock.mockClear();
beaconMock.mockClear();
vi.unstubAllEnvs();
vi.stubEnv("NEXT_PUBLIC_VERCEL_ENV", "production");
vi.stubGlobal("navigator", { sendBeacon: beaconMock });
vi.stubGlobal("navigator", { sendBeacon: beaconMock, webdriver: false });
vi.stubGlobal("Blob", class { constructor(public parts: string[]) {} text() { return this.parts.join(""); } });
});

Expand Down Expand Up @@ -79,6 +79,25 @@
});
});

describe("a browser being driven by a script is not a visitor", () => {
it("counts nothing when navigator.webdriver is set", () => {
// Our own headless checks opened the editor 12 times in one afternoon, and every one
// of them counted. The first numbers anybody read were mostly us.
vi.stubGlobal("navigator", { sendBeacon: beaconMock, webdriver: true });
countEditorOpened("kept");
countFirstEdit();
countExportStarted();
countExportFinished();
expect(trackMock).not.toHaveBeenCalled();
expect(beaconMock).not.toHaveBeenCalled();
});

it("still counts an ordinary browser", () => {
countEditorOpened("kept");
expect(beaconMock).toHaveBeenCalled();
});
});

describe("it cannot carry a person's work, even by accident", () => {
it("sends a template slug only when it looks like one", () => {
countEditorOpened("Our Clinic's Private Draft, 2026");
Expand Down
13 changes: 13 additions & 0 deletions src/lib/funnel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,21 @@ const MAX_EXPORT_MS = 600_000;
*/
let exportStartedAt: number | null = null;

/**
* A browser being driven by a script.
*
* Set by every automation framework and by Chrome's own remote debugging. Our headless
* checks opened the editor a dozen times in one afternoon and all of it counted, so the
* first real numbers were mostly us. A visitor who finishes a site is the whole point of
* these counts, and a robot never does.
*/
function driven(): boolean {
return typeof navigator !== "undefined" && navigator.webdriver === true;
}

function send(name: FunnelEvent, properties?: Record<string, string | number>): void {
if (!process.env.NEXT_PUBLIC_VERCEL_ENV) return;
if (driven()) return;
try {
track(name, properties);
} catch {
Expand Down
Loading