CrawlPodScan your site

Brand measurement

MeasurementEngine, added in 0.7.0, is the counterpart to the AI Readiness Engine's static analysis: it actually queries your configured AI engines, with repeated sampling, and reports whether your brand gets mentioned, recommended, and cited — versus named competitors — each rate with a 95% confidence interval, because a single AI response is not a reliable measurement.

MeasurementEngine

Runs every configured engine adapter against a prompt list (typically from PromptDiscovery) runs times each — default 3, max 10 — and aggregates into a MeasurementReport:

import { MeasurementEngine } from "ai-visibility/measure";
import { OpenAIAdapter, PerplexityAdapter } from "ai-visibility/engines";
import { PromptDiscovery } from "ai-visibility/prompts";

const { clusters } = PromptDiscovery.discover({ brand: "Acme CRM", category: "CRM software", competitors: ["HubSpot"] });

const engine = new MeasurementEngine();
const report = await engine.measure({
  brand: "Acme CRM",
  prompts: clusters.flatMap((c) => c.prompts),
  engines: [new OpenAIAdapter(process.env.OPENAI_API_KEY!), new PerplexityAdapter(process.env.PERPLEXITY_API_KEY!)],
  runs: 3,
  competitors: ["HubSpot"],
});

All calls run through a single sequential queue, grouped by engine — every call to one engine completes, with a 1-second delay between them, before moving to the next engine. Never more than one HTTP call in flight, and never a burst against one provider. A failed call is logged and counted in stats.failedRuns; it is never recorded as a RunResult— fabricating a failure as "not mentioned" would silently bias every rate downward.

The statistics

For each tracked name (the brand, plus every competitor), across every successful run:

  • mentionRate — fraction of runs where the name appeared in the response (case-insensitive substring match).
  • recommendRate — fraction of runs where the name appeared within 2 sentences of a recommendation-context keyword ("recommend", "best", "top pick", etc.) — deliberately simple keyword proximity, not sentiment analysis.
  • averagePosition — mean 1-indexed rank by first-mention order among all tracked names within that response (lower is more prominent); 0 when never mentioned.
  • citationRate — fraction of runs where a cited URL's hostname contains the name's alphanumeric slug ("Acme CRM" → acmecrm, matches acmecrm.com). An approximation — there's no reliable brand-to-domain mapping without asking for one.
  • variance — population variance of the per-run mention indicator (divides by n, not n-1, so a single-run measurement doesn't divide by zero).
  • confidence — 95% confidence interval half-width: 1.96 × √(variance / sampleSize). Report a rate as mentionRate ± confidence; a wide interval means "measure more runs," not "the number is wrong."

CLI: measure

npx ai-visibility measure --brand "Acme CRM" --category "CRM software" --competitors "HubSpot,Pipedrive" --runs 3
npx ai-visibility measure --brand "Acme CRM" --category "CRM software" --json > report.json

measure runs discover internally, queries every configured engine, and prints overall + recommendation-rate bars (brand vs. competitors, each with its confidence interval), a per-engine mention-rate table, and sample-size/duration stats. It resolves engine API keys the same way as every command in this suite — see crawlpod.config.js and environment variables— and throws a clear, actionable error if zero engines resolve a key. Saved --json output can be reused by citations, compare, and report via their --from flag, without re-spending API credits.

Interpreting a result

Read every rate alongside its confidence interval, not in isolation. A brand at 40% mention rate ± 5% and a competitor at 45% ± 30% are not clearly different — the competitor's interval is too wide from too few samples to say so with any confidence; increase runs before concluding anything. perEnginetracks only the primary brand per engine, not competitors — the CLI's "PER ENGINE" display reconstructs a full per-engine-per-competitor breakdown by re-aggregating perPrompt[].runs[] instead.

A low mentionRate alone doesn't say why— that's what citation analysis and competitor gap analysis are for, both of which mine the same MeasurementReport this command produces.