# AI Answer Citation and Brand Presence Auditor (`danielmichalek/ai-answer-citation-auditor`) Actor

Audit supplied AI answers for brand mentions and cited domains. Compare the evidence and export a citation gap checklist. Ready to review your answer samples?

- **URL**: https://apify.com/danielmichalek/ai-answer-citation-auditor.md
- **Developed by:** [Daniel Michałek](https://apify.com/danielmichalek) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$30.00 / 1,000 completed supplied-answer citation audits

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## AI Answer Citation and Brand Presence Auditor

### What it does

Audit AI answers you already collected or are authorized to analyze. Compare literal brand mentions with the domains linked or separately supplied as citations. Each observation retains URL provenance and original text evidence. A report highlights mentions without a tracked first-party citation for human review. This is useful as a dataset QA and reporting step for GEO/AEO and SEO agencies; it does not generate AI answers or query AI providers.

### Input

Supply answers and brands as JSON arrays. Each answer has a unique id and nonempty answer, plus optional query, provider, model, observedAt and citations. Missing metadata stays null or UNSPECIFIED and sourceMetadataVerified remains false. observedAt, when provided, requires a real calendar date and ISO timestamp with seconds and a timezone. Provider labels do not verify which model generated the answer.

Each brand has name, optional aliases and bare domains. Aliases shared across brands are rejected. With includeSubdomains enabled, cross-brand parent/child domain overlap is also rejected. Unicode domains use URL-standard ASCII normalization. www and trailing DNS dots are normalized for domain attribution, with exact suffix boundaries. A hostname such as brand.example.evil.test is not brand.example.

### Output

One dataset report contains answer-level observations, brand summaries, separate supplied provider/model groups, source URL candidates, gap review items and limitations. AUDIT is complete JSON, CITATIONS_CSV is a spreadsheet-safe comparison table and REPORT is a readable Markdown report. Each brand observation is MENTION_AND_CITATION, MENTION_ONLY, CITATION_ONLY or ABSENT.

Mention matching uses literal NFKC-normalized aliases with Unicode letter/number boundaries. URL destinations are masked for prose matching; Markdown link labels remain visible. Overlapping aliases for the same brand count once. Up to three excerpts per answer and brand are copied from the original input with original offsets, while mentionCount includes all non-overlapping matches. Negative statements still contain literal mentions; no sentiment, endorsement or ranking is inferred.

Links in Markdown, reference lists and raw text are URL candidates, not verified supporting evidence. Supplied citations remain explicitly supplied. URL fragments are removed for deduplication, query strings retained, and both inline and supplied provenance survive deduplication. The same domain repeated within one answer does not inflate answer-level coverage. Malformed URLs produce review data; structural input errors fail before a billable report.

sameSuppliedQueryMultiset is true only for multiple groups with exactly identical supplied query strings and sample multiplicities. Missing or different queries keep it false. controlledExperimentVerified is always false because dates, settings and capture conditions are unverified. Rates describe the supplied sample only.

### Pricing and cost control

The report price is USD 0.03 per completed citation-report, for up to200 supplied answers and20 tracked brands. Always verify the current Store price before running. The planning cost estimate is not a cloud measurement. Collection of upstream AI answers is outside this product and can have its own costs. This Actor performs no model inference, paid API calls, provider scraping, proxy use or outbound data requests.

The total input limit is3MB, each answer30000 characters, combined inline and supplied URL candidates100 per answer, up to10 aliases and10 domains per brand. maxAnswers can lower the limit. The serialized report has a7MB safety cap because repeated evidence can expand beyond input size; split unusually large reports into smaller batches. Overflow fails before exports and without partial report billing. Exports are saved before the single report emission. A valid sample with no tracked mentions still returns one report.

### Limitations and fair use

This is an offline pilot, not a provider-wide visibility tracker. It cannot verify link availability, page content, citation entailment, source accuracy, model identity or domain ownership. Inline links may be examples or incidental URLs. A mention without a tracked citation is a review observation, not proof of a marketing failure or an SEO recommendation by itself. Short aliases can create incidental matches.

Input and reports use Apify run storage under its retention settings. Do not upload secrets, private chat exports or personal customer records without authorization. Nothing is sent to a third-party AI provider. No ads, budgets, accounts or customer websites are changed.

### Example

examples/input.json contains two synthetic answers to the same query from two explicitly fictional engine labels and two tracked brands. It yields two unique answer-level URL candidates and three mention-only review items. Run npm ci --ignore-scripts, npm test, then the existing factory release.mjs --local-run --write-example. The source remains in this Actor directory; Apifi boty is a generated view.

# Actor input Schema

## `answers` (type: `array`):

1 to 200 objects: unique string id, answer text (up to30000 characters), optional query, provider, model, observedAt and citations. citations can be URL strings or objects with url. Labels and capture dates remain unverified customer metadata. Prefilled values are synthetic demonstration data; replace them with your own samples.

## `brands` (type: `array`):

1 to20 objects with name, optional aliases (up to10), and domains (1 to10 bare DNS names). Domains and aliases cannot overlap ambiguously across brands. No ownership or endorsement is inferred. Prefilled values are synthetic demonstration data; replace them with your own samples.

## `includeSubdomains` (type: `boolean`):

When enabled, docs.example.com counts for tracked example.com. Exact domain boundaries are always enforced.

## `maxAnswers` (type: `integer`):

Hard cap; overflow fails without truncation. Total input cap3MB, combined inline plus supplied URL candidates100 per answer.

## `maxItems` (type: `integer`):

Exactly one completed report per run, saved before report billing emission.

## Actor input object example

```json
{
  "answers": [
    {
      "id": "sample-a",
      "query": "Analytics for small shops",
      "provider": "Sample engine A",
      "answer": "Acme Analytics is one option. See [Acme guide](https://docs.acme.example/guide?utm_source=demo). Northstar is also mentioned.",
      "citations": [
        {
          "url": "https://docs.acme.example/guide?utm_source=demo#top"
        }
      ]
    },
    {
      "id": "sample-b",
      "query": "Analytics for small shops",
      "provider": "Sample engine B",
      "answer": "Northstar is an option. [Independent comparison](https://review.example/compare) mentions Acme without linking its site."
    }
  ],
  "brands": [
    {
      "name": "Acme",
      "aliases": [
        "Acme Analytics"
      ],
      "domains": [
        "acme.example"
      ]
    },
    {
      "name": "Northstar",
      "domains": [
        "northstar.example"
      ]
    }
  ],
  "includeSubdomains": true,
  "maxAnswers": 200,
  "maxItems": 1
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `csv` (type: `string`):

No description

## `report` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "answers": [
        {
            "id": "sample-a",
            "query": "Analytics for small shops",
            "provider": "Sample engine A",
            "answer": "Acme Analytics is one option. See [Acme guide](https://docs.acme.example/guide?utm_source=demo). Northstar is also mentioned.",
            "citations": [
                {
                    "url": "https://docs.acme.example/guide?utm_source=demo#top"
                }
            ]
        },
        {
            "id": "sample-b",
            "query": "Analytics for small shops",
            "provider": "Sample engine B",
            "answer": "Northstar is an option. [Independent comparison](https://review.example/compare) mentions Acme without linking its site."
        }
    ],
    "brands": [
        {
            "name": "Acme",
            "aliases": [
                "Acme Analytics"
            ],
            "domains": [
                "acme.example"
            ]
        },
        {
            "name": "Northstar",
            "domains": [
                "northstar.example"
            ]
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("danielmichalek/ai-answer-citation-auditor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "answers": [
        {
            "id": "sample-a",
            "query": "Analytics for small shops",
            "provider": "Sample engine A",
            "answer": "Acme Analytics is one option. See [Acme guide](https://docs.acme.example/guide?utm_source=demo). Northstar is also mentioned.",
            "citations": [{ "url": "https://docs.acme.example/guide?utm_source=demo#top" }],
        },
        {
            "id": "sample-b",
            "query": "Analytics for small shops",
            "provider": "Sample engine B",
            "answer": "Northstar is an option. [Independent comparison](https://review.example/compare) mentions Acme without linking its site.",
        },
    ],
    "brands": [
        {
            "name": "Acme",
            "aliases": ["Acme Analytics"],
            "domains": ["acme.example"],
        },
        {
            "name": "Northstar",
            "domains": ["northstar.example"],
        },
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("danielmichalek/ai-answer-citation-auditor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "answers": [
    {
      "id": "sample-a",
      "query": "Analytics for small shops",
      "provider": "Sample engine A",
      "answer": "Acme Analytics is one option. See [Acme guide](https://docs.acme.example/guide?utm_source=demo). Northstar is also mentioned.",
      "citations": [
        {
          "url": "https://docs.acme.example/guide?utm_source=demo#top"
        }
      ]
    },
    {
      "id": "sample-b",
      "query": "Analytics for small shops",
      "provider": "Sample engine B",
      "answer": "Northstar is an option. [Independent comparison](https://review.example/compare) mentions Acme without linking its site."
    }
  ],
  "brands": [
    {
      "name": "Acme",
      "aliases": [
        "Acme Analytics"
      ],
      "domains": [
        "acme.example"
      ]
    },
    {
      "name": "Northstar",
      "domains": [
        "northstar.example"
      ]
    }
  ]
}' |
apify call danielmichalek/ai-answer-citation-auditor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,danielmichalek/ai-answer-citation-auditor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/eRluuRDPnkUOPLC3b/builds/Y0Si6H9ygpCLjjww8/openapi.json
