---
title: "Build a Weekly AI Brand Monitor With Sheets, Two APIs, and 25 Buyer Prompts"
description: "Use your own search terms to track brand mentions and competitors in ChatGPT and Perplexity API answers. Set up the Sheet, script, weekly run, and report."
url: "https://groas.com/post/build-your-own-ai-brand-monitor-in-an-af"
image: "https://pub-87da24ecbbfc4c3bad6875f3aa013712.r2.dev/generated-images/6d5c302b-3ffa-4a3c-a170-b00600ca2cd6.png"
published: "2026-10-09T05:38:01.436Z"
modified: "2026-10-09T05:38:01.499Z"
---

October 9, 2026 · 10 min read

# Build a Weekly AI Brand Monitor With Sheets, Two APIs, and 25 Buyer Prompts

[Alexander PerelmanHead Of Product @ groas](https://groas.com/author/alexander-perelman)[LinkedIn](https://www.linkedin.com/in/alexander-433793253/)

![A tabletop model town where tiny people queue at two oracle booths while a clerk ticks red marks on a paving-stone spreadsheet at dawn.](https://pub-87da24ecbbfc4c3bad6875f3aa013712.r2.dev/generated-images/6d5c302b-3ffa-4a3c-a170-b00600ca2cd6.png)

In this article

1. [1. Freeze 25 questions buyers actually ask](#1-freeze-25-questions-buyers-actually-ask)
2. [2. Give the Sheet a structure the script can use](#2-give-the-sheet-a-structure-the-script-can-use)
3. [3. Store the API keys outside the Sheet](#3-store-the-api-keys-outside-the-sheet)
4. [4. Paste the script and set your names](#4-paste-the-script-and-set-your-names)
5. [5. Schedule Monday, then test it by hand](#5-schedule-monday-then-test-it-by-hand)
6. [6. Turn the rows into a loss list](#6-turn-the-rows-into-a-loss-list)
7. [Verify the monitor—and know where DIY stops](#verify-the-monitorand-know-where-diy-stops)

A small business does not need another monitoring subscription to find out whether AI answers name it—or name a competitor instead. I used to paste buyer questions into ChatGPT one by one and copy the answers into a sheet. It worked for an afternoon. By the next week, the answers were stale.

This walkthrough gives you a repeatable version: **25 prompts drawn from your own search demand**, sent three times each to OpenAI and Perplexity every week. You will get a Google Sheet that shows which prompts mention your brand and which name a competitor instead. You need a Google account, access to Search Console and your Google Ads search terms report, two API keys, and roughly three hours to build it. Put $10 in credit on each API account to start; usage depends on the answers returned.

## 1. Freeze 25 questions buyers actually ask

Open Search Console: `Performance > Queries`. Set the date range to the last 90 days, sort by impressions, and export the top 50 queries. Then open Google Ads: `Campaigns > Insights and reports > Search terms`. Use the same date range and export that report too.

Rewrite 25 terms as full buyer questions. Use this mix:

- **10 category prompts:** `best CRM for a 5-person plumbing company`
- **7 problem prompts:** `how do I stop no-show appointments for quotes`
- **5 comparison prompts:** `Acme vs Beta for service scheduling`
- **3 brand prompts:** `does [YourBrand] do weekend installs`

Build these from [buyer language rather than a brainstorm](https://justinmckelvey.com/blog/track-brand-mentions-in-ai). Category and problem questions deserve most of the slots because they show where you compete before someone knows your name.

**Expected result:** a list of 25 questions you can keep unchanged for 90 days. The mistake here is rewriting a question every Monday because its wording embarrasses you. Leave it. That embarrassment is data. If a question genuinely goes stale, you will deactivate it rather than erase its history.

## 2. Give the Sheet a structure the script can use

Create a Google Sheet named `AI monitor`. Add five tabs, spelled exactly `prompts`, `runs`, `mentions`, `competitors`, and `citations`. Put these headers in row 1:

| Tab           | Headers, in order                                                                                              |
| ------------- | -------------------------------------------------------------------------------------------------------------- |
| `prompts`     | `prompt_id`, `prompt_text`, `intent`, `active`                                                                 |
| `runs`        | `timestamp`, `prompt_id`, `model`, `run_n`, `answer_text`, `brand_mentioned`, `competitor_names`, `urls_cited` |
| `mentions`    | `prompt_id`, `model`, `mention_rate`                                                                           |
| `competitors` | `prompt_id`, `model`, `competitor`, `hits`                                                                     |
| `citations`   | `prompt_id`, `model`, `url`                                                                                    |

In `prompts!A2:A26`, enter `P01` through `P25`. Paste the questions into `prompts!B2:B26`, tag each one in column C as `category`, `problem`, `comparison`, or `brand`, and select `prompts!D2:D26`. Click `Data > Data validation`, set the criteria to `Checkbox`, and check every box. Leave the other tabs empty below their headers.

**Expected result:** 25 active rows in `prompts` and no run data yet. The mistake is pasting questions into column A: the script reads IDs from A and questions from B. The checkbox is your kill switch. **Deactivate a stale prompt; never delete its row.**

![Paper prompt cards feeding two small API machines beside a spreadsheet](https://pub-87da24ecbbfc4c3bad6875f3aa013712.r2.dev/generated-images/a8618fa7-9934-416f-9775-ab72b25a7c7a.png)

## 3. Store the API keys outside the Sheet

Create an OpenAI key at `platform.openai.com > API Keys > Create new secret key` and a Perplexity key at `perplexity.ai > Settings > API > Generate`. In the Sheet, open `Extensions > Apps Script`, then `Project Settings > Script Properties > Add property`. Store the keys under these exact names:

- `OPENAI_KEY`
- `PERPLEXITY_KEY`

Set a spending limit or alert in each provider’s billing settings before the first run. This setup makes **25 prompts × 2 models × 3 answers = 150 API calls** per completed weekly run. The bill depends on usage, not just the number of prompts.

**Expected result:** two script properties, with no key in a cell or in the code. The mistake is pasting a key into `Code.gs` and later sharing the Sheet. Caps and alerts come before the first test, not after a surprisingly busy Monday.

![Paper spreadsheet with prompt cards feeding two API machines and filling mention trays](https://pub-87da24ecbbfc4c3bad6875f3aa013712.r2.dev/generated-images/e7a163b4-1092-4eb3-93e4-dbf8ec4ad334.png)

## 4. Paste the script and set your names

In `Extensions > Apps Script`, open `Code.gs`, delete its contents, and paste the complete block below. Edit `BRAND_NAMES`, `COMPETITORS`, and `DOMAIN` at the top. Keep every name lowercase. Include the short name customers use, not only the legal name. Check the two model IDs against the models available to your API accounts before running.

The script requests three answers per active prompt from each API, stores the answers, and checks them for the names you supplied. It records citations returned in the Perplexity response. A failed call stops the run instead of being counted as a `FALSE` mention; if the run nears Apps Script’s [six-minute execution limit](https://magesheet.com/blog/google-workspace-ai-automation), a continuation trigger picks up the remaining calls.

![Marketer comparing three different AI answers to the same prompt](https://pub-87da24ecbbfc4c3bad6875f3aa013712.r2.dev/generated-images/eedd22e9-79fa-45da-83ce-66c3432d3d38.png)

```js
const BRAND_NAMES = ['acme plumbing'];
const COMPETITORS = ['beta drains', 'gamma rooter'];
const DOMAIN = 'acmeplumbing.com';
const MODELS = [
  { id: 'openai', model: 'gpt-4o-mini' },
  { id: 'perplexity', model: 'sonar' }
];

function runMonitorOnce() {
  const props = PropertiesService.getScriptProperties();
  const openaiKey = props.getProperty('OPENAI_KEY');
  const perplexityKey = props.getProperty('PERPLEXITY_KEY');
  if (!openaiKey || !perplexityKey) throw new Error('Missing API key');

  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const promptRows = ss.getSheetByName('prompts').getDataRange().getValues();
  const runs = ss.getSheetByName('runs');
  const citations = ss.getSheetByName('citations');
  const jobs = [];
  for (let i = 1; i < promptRows.length; i++) {
    if (promptRows[i][3] !== true) continue;
    for (const m of MODELS) {
      for (let n = 1; n <= 3; n++) {
        jobs.push({ pid: promptRows[i][0], q: promptRows[i][1], m, n });
      }
    }
  }

  const saved = props.getProperty('MONITOR_PROGRESS');
  const state = saved ? JSON.parse(saved) : {
    next: 0, timestamp: new Date().toISOString()
  };
  if (!saved) props.setProperty('MONITOR_PROGRESS', JSON.stringify(state));
  const started = Date.now();

  for (let i = state.next; i < jobs.length; i++) {
    if (Date.now() - started > 5 * 60 * 1000) {
      scheduleResume();
      return;
    }
    const job = jobs[i];
    const answer = fetchWithRetry(job.m, job.q, openaiKey, perplexityKey);
    const text = answer.text.toLowerCase();
    const named = BRAND_NAMES.some(name => text.includes(name.toLowerCase()));
    const competitors = COMPETITORS.filter(name =>
      text.includes(name.toLowerCase())
    );

    runs.appendRow([
      state.timestamp, job.pid, job.m.id, job.n, answer.text,
      named, competitors.join('; '), answer.urls.join('; ')
    ]);
    for (const url of answer.urls) {
      citations.appendRow([job.pid, job.m.id, url]);
    }
    state.next = i + 1;
    props.setProperty('MONITOR_PROGRESS', JSON.stringify(state));
    Utilities.sleep(1000);
  }
  props.deleteProperty('MONITOR_PROGRESS');
  clearResumeTriggers();
}

function fetchWithRetry(m, q, openaiKey, perplexityKey) {
  const isOpenAI = m.id === 'openai';
  const url = isOpenAI
    ? 'https://api.openai.com/v1/chat/completions'
    : 'https://api.perplexity.ai/chat/completions';
  const key = isOpenAI ? openaiKey : perplexityKey;
  const request = {
    model: m.model,
    messages: [{ role: 'user', content: q }]
  };
  if (!isOpenAI) request.return_citations = true;

  for (let attempt = 1; attempt <= 3; attempt++) {
    try {
      const response = UrlFetchApp.fetch(url, {
        method: 'post',
        contentType: 'application/json',
        headers: { Authorization: 'Bearer ' + key },
        payload: JSON.stringify(request),
        muteHttpExceptions: true
      });
      const status = response.getResponseCode();
      if (status < 200 || status >= 300) {
        throw new Error(m.id + ' returned HTTP ' + status);
      }
      const data = JSON.parse(response.getContentText());
      const text = data.choices[0].message.content;
      if (!text) throw new Error(m.id + ' returned an empty answer');
      return {
        text,
        urls: isOpenAI ? [] : (data.citations || [])
      };
    } catch (error) {
      if (attempt === 3) throw error;
      Utilities.sleep(2000 * attempt);
    }
  }
}

function scheduleResume() {
  const exists = ScriptApp.getProjectTriggers().some(trigger =>
    trigger.getHandlerFunction() === 'resumeMonitor'
  );
  if (!exists) {
    ScriptApp.newTrigger('resumeMonitor').timeBased().after(60000).create();
  }
}

function resumeMonitor() {
  clearResumeTriggers();
  runMonitorOnce();
}

function clearResumeTriggers() {
  for (const trigger of ScriptApp.getProjectTriggers()) {
    if (trigger.getHandlerFunction() === 'resumeMonitor') {
      ScriptApp.deleteTrigger(trigger);
    }
  }
}
```

**Expected result:** `Run > runMonitorOnce` eventually adds 150 rows to `runs` if all 25 prompts are active. You may see fewer at first while a continuation is pending. If an API call fails after three attempts, inspect the error in Apps Script’s `Executions` view and rerun `runMonitorOnce` after fixing it; the saved progress starts at the failed call.

The mistake is treating a blank answer as a non-mention. That turns an outage into a visibility problem. There is one narrow edge case worth knowing: if Apps Script stops after writing a row but before saving progress, a retry can duplicate that row. Check for duplicate `timestamp`, `prompt_id`, `model`, and `run_n` values before using the report.

I used to tell clients one answer was enough. I was wrong. One answer is an anecdote. **Three answers give you a mention rate**, though not a verdict on what every customer sees.

## 5. Schedule Monday, then test it by hand

In Apps Script, click `Triggers` (the clock icon) > `+ Add Trigger`. Choose `runMonitorOnce`, `Time-driven`, `Week timer`, `Every Monday`, and `6am to 7am`. Save and approve the permissions. Enable failure notifications to your email.

Now use `Run > runMonitorOnce` for the first test. Open `runs` and check that `answer_text` contains answers, `brand_mentioned` contains `TRUE` or `FALSE`, and each completed prompt has three rows per model under the same timestamp. Check `citations` for URLs returned by Perplexity; an empty cell for OpenAI is expected because this script does not collect citations from that response.

**Expected result:** one weekly trigger, plus a populated first run. The mistake is scheduling an untested script and discovering a permissions or key error the following Monday. If the first run is still continuing, let it finish before judging the row count.

## 6. Turn the rows into a loss list

In `mentions`, enter one row for every `prompt_id` and model pair: `P01` with `openai`, `P01` with `perplexity`, then the same pair for `P02` through `P25`. In `mentions!C2`, paste this formula and fill it down:

```text
=IFERROR(COUNTIFS(runs!B:B,A2,runs!C:C,B2,runs!F:F,TRUE)/COUNTIFS(runs!B:B,A2,runs!C:C,B2),"")
```

Format column C as a percentage. This calculates **brand mentions divided by completed answers** for each prompt and model. Once the first complete run is in, a brand named in two of three answers shows `67%`. As weekly runs accumulate, the formula uses all completed answers for that pair. Blank means there are none yet; it does not mean `0%`.

Select the filled `mentions` table and use `Insert > Chart` to chart mention rate by prompt. Keep the two models identifiable rather than combining them into an invented single ranking. [Repeated mention rate beats a single-run position](https://ecommercefastlane.com/how-to-choose-an-ai-visibility-tracker/).

In `competitors`, enter the prompt IDs and model names you want to inspect, and put a competitor name from your script’s list in column C. In `competitors!D2`, paste this formula and fill it down:

```text
=COUNTIFS(runs!B:B,A2,runs!C:C,B2,runs!G:G,"*"&C2&"*")
```

That counts completed answers containing that competitor name. It is not a percentage, and it uses the same simple text matching as the script. Sort `mentions` from lowest to highest, then check those prompt-and-model pairs against `competitors`. A `0%` brand rate next to repeated competitor hits is the list to work. Search Console gives you query demand; it does not tell you [whether your entity appeared inside an AI answer](https://llmclicks.ai/knowledge-hub/ai-overviews/google-ai-overviews-optimization/).

**Expected result:** a chart of brand mention rates and a competitor hit count for the prompts you inspect. The mistake is seeing one lost answer and rewriting a page by lunch. Wait for two weekly runs before treating a pattern as a pattern. If the loss persists, use the [buyer prompts you lose](https://groas.com/post/stop-asking-which-prompts-mention-your-b) to decide what content needs work. **Fix the alias list before concluding your brand is invisible.** A shorter customer name that the script does not recognise can make a real mention look like a loss.

## Verify the monitor—and know where DIY stops

After a completed Monday run, filter `runs` to its timestamp. With all prompts active, you should have **150 rows: three answers per prompt per model**. Confirm that the answers are populated, the `mentions` percentages calculate, and the lowest-rate prompts can be matched to competitor hits. If the counts are short, check Apps Script `Executions` and any pending continuation trigger before editing the report.

Then make the first change that matters: pick the three persistent `0%` prompts with the highest impressions in Search Console and inspect the pages behind them. The sheet identifies a loss; it does not rewrite a service page, publish a comparison, or earn a citation for you. Work one prompt at a time and watch the next two cycles.

Keep the measurement boundary in view. **API answers are a repeatable proxy, not the consumer apps.** App answers can differ because of memory, personalisation, location, and tools; a [measurement guide found limited source overlap](https://github.com/hacktheseo/wordpress-seo-skills/blob/HEAD/skills/ai-visibility-tracker/references/measurement.md) between API and app results. This script also checks names with simple text matching. It does not judge whether a mention is a recommendation, and its `citations` tab records the Perplexity URLs returned by the API, not every link a reader might see.

Google AI Overviews stay outside this build too. There is no public API for querying them through this script, so do not label the chart ‘all AI search’. It measures these two API workflows. If the loss list grows faster than you can act on it, the DIY version has reached its limit. Compare [done-with-you and done-for-you execution](https://groas.com/post/done-with-you-vs-done-for-you-google-ads-dwy-dfy-comparison) before paying someone to do more monitoring. Keep the 25 prompts stable and the Monday trigger on. The first thing to change is the page behind a losing buyer question, not the colour of the chart.

## Frequently Asked Questions

### Where should the 25 buyer prompts for an AI brand monitor come from?

Take them from your own search demand: export the top 50 queries from Search Console (last 90 days, sorted by impressions) and the search terms report from Google Ads, then rewrite 25 of those terms as full buyer questions. Use a mix of about 10 category, 7 problem, 5 comparison, and 3 brand prompts, and keep the list unchanged for 90 days.

### Should I delete a prompt row from the Sheet when a question goes stale?

No. Use the checkbox in the prompts tab as a kill switch: deactivate the stale prompt and leave its row and history intact. The script reads IDs from column A and questions from column B, so deleting rows would break both the history and the script's references.

### Where do I put my OpenAI and Perplexity API keys for the Sheet?

Store them as script properties in Apps Script under the exact names OPENAI_KEY and PERPLEXITY_KEY, not in any cell or in Code.gs, so sharing the Sheet never exposes them. Set a spending limit or alert in each provider's billing settings before the first run, and put about $10 of credit on each account to start.

### How many API calls does one weekly run of the brand monitor make?

A completed run with all 25 prompts active makes 150 API calls: 25 prompts times 2 models (OpenAI and Perplexity) times 3 answers each. The bill depends on the usage of those calls, not just the number of prompts.

### Why send each prompt three times instead of just once?

One answer is an anecdote; three answers per prompt per model give you a mention rate, such as 67% when a brand appears in two of three answers. A failed call stops the run instead of being counted as a FALSE mention, so an API outage does not get misread as a visibility problem.

### How do I schedule the monitor to run weekly in Apps Script?

Add a trigger in Apps Script for runMonitorOnce, set to Time-driven, Week timer, every Monday between 6am and 7am, and enable failure notifications to your email. Run the function manually first to confirm answers, TRUE/FALSE brand_mentioned values, and citations appear, so you do not discover a permissions or key error the following Monday.

### How do I find which prompts I am losing to competitors?

The mentions formula divides brand mentions by completed answers for each prompt and model, so sort it from lowest to highest and check those pairs against the competitors tab, which counts answers containing a competitor's name. A 0% brand rate next to repeated competitor hits is the loss list to work on. Wait for two weekly runs before treating a pattern as a pattern.

### Does this monitor measure ChatGPT and Perplexity apps and Google AI Overviews?

No. The script queries the OpenAI and Perplexity APIs, which are a repeatable proxy rather than the consumer apps, where answers can differ because of memory, personalisation, location, and tools. Google AI Overviews have no public API for this build, so do not label the chart all AI search, and note the script matches names by simple text matching without judging whether a mention is a recommendation.

## Pay For Results, Not For Hours

Businesses buy the outcome, agencies resell it, and groas answers for it either way.

[See If You Qualify](https://groas.typeform.com/to/xC1bQNUT)

## Structured data

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://graph.groas.com/entity/groas","name":"groas","url":"https://groas.com/","logo":{"@type":"ImageObject","url":"https://groas.com/icon-512.png","width":512,"height":512},"sameAs":["https://www.linkedin.com/company/groas/"]},{"@type":"WebSite","@id":"https://groas.com/#website","name":"groas","url":"https://groas.com/","inLanguage":"en-US","publisher":{"@id":"https://graph.groas.com/entity/groas"}},{"@type":"WebPage","@id":"https://groas.com/post/build-your-own-ai-brand-monitor-in-an-af#webpage","url":"https://groas.com/post/build-your-own-ai-brand-monitor-in-an-af","name":"Build a Weekly AI Brand Monitor With Sheets, Two APIs, and 25 Buyer Prompts","description":"Use your own search terms to track brand mentions and competitors in ChatGPT and Perplexity API answers. Set up the Sheet, script, weekly run, and report.","inLanguage":"en-US","isPartOf":{"@id":"https://groas.com/#website"},"about":{"@id":"https://graph.groas.com/entity/groas"},"primaryImageOfPage":{"@type":"ImageObject","url":"https://pub-87da24ecbbfc4c3bad6875f3aa013712.r2.dev/generated-images/6d5c302b-3ffa-4a3c-a170-b00600ca2cd6.png"},"breadcrumb":{"@id":"https://groas.com/post/build-your-own-ai-brand-monitor-in-an-af#breadcrumb"},"dateModified":"2026-10-09T05:38:01.499Z","mainEntity":{"@id":"https://groas.com/post/build-your-own-ai-brand-monitor-in-an-af#article"}},{"@type":"BreadcrumbList","@id":"https://groas.com/post/build-your-own-ai-brand-monitor-in-an-af#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://groas.com/"},{"@type":"ListItem","position":2,"name":"Blog","item":"https://groas.com/blog"},{"@type":"ListItem","position":3,"name":"Build a Weekly AI Brand Monitor With Sheets, Two APIs, and 25 Buyer Prompts","item":"https://groas.com/post/build-your-own-ai-brand-monitor-in-an-af"}]},{"@type":"BlogPosting","@id":"https://groas.com/post/build-your-own-ai-brand-monitor-in-an-af#article","url":"https://groas.com/post/build-your-own-ai-brand-monitor-in-an-af","mainEntityOfPage":{"@id":"https://groas.com/post/build-your-own-ai-brand-monitor-in-an-af#webpage"},"isPartOf":{"@id":"https://groas.com/blog#blog"},"headline":"Build a Weekly AI Brand Monitor With Sheets, Two APIs, and 25 Buyer Prompts","description":"Use your own search terms to track brand mentions and competitors in ChatGPT and Perplexity API answers. Set up the Sheet, script, weekly run, and report.","datePublished":"2026-10-09T05:38:01.436Z","dateModified":"2026-10-09T05:38:01.499Z","image":{"@type":"ImageObject","url":"https://pub-87da24ecbbfc4c3bad6875f3aa013712.r2.dev/generated-images/6d5c302b-3ffa-4a3c-a170-b00600ca2cd6.png"},"author":{"@id":"https://groas.com/author/alexander-perelman#person"},"publisher":{"@id":"https://graph.groas.com/entity/groas"},"keywords":"const, prompts, brand, api, answers, script, run, weekly","wordCount":2162,"inLanguage":"en-US"},{"@type":"Person","@id":"https://groas.com/author/alexander-perelman#person","name":"Alexander Perelman","jobTitle":"Head Of Product @ groas","description":"Ex Goldman Sachs and Ex Stanford Computer Science","image":"https://groas.com/media/blog/4f17cac3a81acc224cc1b2cfab8f94bbc295a3089d13e8421125771ef8d4064f.jpg","worksFor":{"@id":"https://graph.groas.com/entity/groas"},"sameAs":["https://www.linkedin.com/in/alexander-433793253/"]},{"@type":"FAQPage","@id":"https://groas.com/post/build-your-own-ai-brand-monitor-in-an-af#faq","mainEntity":[{"@type":"Question","name":"Where should the 25 buyer prompts for an AI brand monitor come from?","acceptedAnswer":{"@type":"Answer","text":"Take them from your own search demand: export the top 50 queries from Search Console (last 90 days, sorted by impressions) and the search terms report from Google Ads, then rewrite 25 of those terms as full buyer questions. Use a mix of about 10 category, 7 problem, 5 comparison, and 3 brand prompts, and keep the list unchanged for 90 days."}},{"@type":"Question","name":"Should I delete a prompt row from the Sheet when a question goes stale?","acceptedAnswer":{"@type":"Answer","text":"No. Use the checkbox in the prompts tab as a kill switch: deactivate the stale prompt and leave its row and history intact. The script reads IDs from column A and questions from column B, so deleting rows would break both the history and the script's references."}},{"@type":"Question","name":"Where do I put my OpenAI and Perplexity API keys for the Sheet?","acceptedAnswer":{"@type":"Answer","text":"Store them as script properties in Apps Script under the exact names OPENAI_KEY and PERPLEXITY_KEY, not in any cell or in Code.gs, so sharing the Sheet never exposes them. Set a spending limit or alert in each provider's billing settings before the first run, and put about $10 of credit on each account to start."}},{"@type":"Question","name":"How many API calls does one weekly run of the brand monitor make?","acceptedAnswer":{"@type":"Answer","text":"A completed run with all 25 prompts active makes 150 API calls: 25 prompts times 2 models (OpenAI and Perplexity) times 3 answers each. The bill depends on the usage of those calls, not just the number of prompts."}},{"@type":"Question","name":"Why send each prompt three times instead of just once?","acceptedAnswer":{"@type":"Answer","text":"One answer is an anecdote; three answers per prompt per model give you a mention rate, such as 67% when a brand appears in two of three answers. A failed call stops the run instead of being counted as a FALSE mention, so an API outage does not get misread as a visibility problem."}},{"@type":"Question","name":"How do I schedule the monitor to run weekly in Apps Script?","acceptedAnswer":{"@type":"Answer","text":"Add a trigger in Apps Script for runMonitorOnce, set to Time-driven, Week timer, every Monday between 6am and 7am, and enable failure notifications to your email. Run the function manually first to confirm answers, TRUE/FALSE brand_mentioned values, and citations appear, so you do not discover a permissions or key error the following Monday."}},{"@type":"Question","name":"How do I find which prompts I am losing to competitors?","acceptedAnswer":{"@type":"Answer","text":"The mentions formula divides brand mentions by completed answers for each prompt and model, so sort it from lowest to highest and check those pairs against the competitors tab, which counts answers containing a competitor's name. A 0% brand rate next to repeated competitor hits is the loss list to work on. Wait for two weekly runs before treating a pattern as a pattern."}},{"@type":"Question","name":"Does this monitor measure ChatGPT and Perplexity apps and Google AI Overviews?","acceptedAnswer":{"@type":"Answer","text":"No. The script queries the OpenAI and Perplexity APIs, which are a repeatable proxy rather than the consumer apps, where answers can differ because of memory, personalisation, location, and tools. Google AI Overviews have no public API for this build, so do not label the chart all AI search, and note the script matches names by simple text matching without judging whether a mention is a recommendation."}}]}]}
```
