# Chinese AI Crawler Access Checker for robots.txt (`zinin/chinese-ai-crawler-access-checker`) Actor

Audit buyer websites through robots.txt and llms.txt. Export a Chinese crawler path matrix, explicit score denominators and bot catalog provenance.

- **URL**: https://apify.com/zinin/chinese-ai-crawler-access-checker.md
- **Developed by:** [Tim Zinin](https://apify.com/zinin) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $14.00 / 1,000 sites

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Chinese AI Crawler Access Checker for robots.txt

Check Chinese AI crawler access through buyer websites’ robots.txt and optional llms.txt. Export a bot-by-path formal policy matrix, explicit score denominators and catalog provenance without downloading the homepage.

**Evidence status: private build 0.1.2 accepted on 2026-09-06.** Every input/output example below is an exact Dataset record from accepted runs on Apify's network with the pay-per-event tariff active. The listing is not public yet; no scheduled task or review history is claimed.

### What you get

- Only robots.txt and llms.txt are requested
- Twenty local candidate tokens with reported/unverified provenance
- Longest-match rules, merged groups, percent encoding and Allow ties
- Known-check score denominators, unknown cells and matched-rule explanations
- Runs on Apify: schedule it, monitor it, call it through the platform API, and export the dataset as JSON, CSV or Excel.

![Source workflow](assets/readme-workflow.svg)

### How to run it

1. Open the actor input form and review the supplied prefill.
2. Replace the scope with sources you are authorized to process, or use the reviewed prefill for a first check.
3. Set a small result limit and an appropriate run budget.
4. Start the run, then inspect both the dataset and the OUTPUT record.
5. Filter complete rows before connecting an export or unattended schedule.

### Pricing

Active tariff on the private build: **$0.005 per run start + $0.020 per complete website audit** through the `result-found` event.

For 100 complete payable units, the planned event total is **$2.005**, including one start. Free absence, source errors, incomplete requested work and notices do not add a result event. A run-start event can still apply even when every result row is free.

### Input

This is the schema prefill used for the key-free daily run contract. Optional secrets have no prefill. Array lengths and structural limits are checked again in the runtime before source work.

```json
{
  "sites": [
    "https://example.com",
    "https://apify.com"
  ],
  "paths": [
    "/"
  ],
  "bots": [
    "Baiduspider",
    "Baidubot",
    "Bytespider",
    "Bytedance",
    "Doubao",
    "DeepSeekBot",
    "ChatGLM-Spider",
    "Qwenbot",
    "PanguBot",
    "PetalBot",
    "Kimi",
    "Hunyuan",
    "YiBot",
    "SenseBot",
    "iFlytekBot",
    "MiniMaxBot",
    "InternLMBot",
    "360Spider",
    "Sogou web spider",
    "Yisouspider"
  ],
  "checkLlms": true,
  "maxItems": 2
}
```

| Field | Meaning |
|---|---|
| `sites` | Buyer website origins. HTTPS public hosts only, no path or query. The website homepage is never downloaded. |
| `paths` | Paths for formal matching. Up to 10 paths of 500 characters; these paths are evaluated locally and never fetched. |
| `bots` | Catalog labels. Choose from the 20 actor-local candidates; provenance distinguishes reported and unverified tokens. |
| `checkLlms` | Check llms.txt. Fetch only after robots allows our llms path; missing 404 is known absence, failures are unknown. |
| `maxItems` | Maximum sites. At most 50; sites times paths times bots must not exceed 10000. |

### Output

The record below is exact. Run `1OgbI79U4RmBr3GUh` on build 0.1.2, 2026-09-06, 1 s, Dataset records: 1, charged events: `{"apify-actor-start": 1, "result-found": 1}`. 1 paid record(s). Input: `{"sites": ["https://example.com"], "checkLlms": true, "maxItems": 2}`.

```json
{
 "schemaVersion": "1.0",
 "type": "audit",
 "sourceUrl": "https://example.com/robots.txt",
 "found": true,
 "status": "found",
 "resultCount": 1,
 "partial": false,
 "error": "",
 "warnings": [
  "formal_rules_do_not_guarantee_behavior",
  "catalog_contains_unconfirmed_tokens"
 ],
 "checkedAt": "2026-09-06T06:37:49.564Z",
 "evidence": {
  "kind": "robots_and_llms_metadata",
  "robotsUrl": "https://example.com/robots.txt"
 },
 "confidence": "source_metadata",
 "action": "review",
 "website": "https://example.com",
 "aiAccessScore": 100,
 "aiAccessNumerator": 20,
 "aiAccessDenominator": 20,
 "aiAccessUnknown": 0,
 "aiSearchScore": null,
 "aiSearchNumerator": 0,
 "aiSearchDenominator": 0,
 "aiSearchUnknown": 0,
 "robotsTxt": {
  "exists": false,
  "statusCode": 404,
  "url": "https://example.com/robots.txt"
 },
 "llmsTxt": {
  "exists": false,
  "statusCode": 404,
  "url": "https://example.com/llms.txt",
  "status": "not_found"
 },
 "blockedBots": [],
 "summary": "20/20 known formal path checks allowed; 0 unknown. Bot existence and traffic are separate observations.",
 "matrix": [
  {
   "bot": "Baiduspider",
   "matchToken": "Baiduspider",
   "path": "/",
   "allowed": true,
   "matchedRule": null,
   "group": [],
   "verificationStatus": "reported",
   "type": "search",
   "…": "1 more keys omitted here for length"
  },
  {
   "bot": "Baidubot",
   "matchToken": "Baidubot",
   "path": "/",
   "allowed": true,
   "matchedRule": null,
   "group": [],
   "verificationStatus": "unverified",
   "type": "unknown",
   "…": "1 more keys omitted here for length"
  },
  {
   "bot": "Bytespider",
   "matchToken": "Bytespider",
   "path": "/",
   "allowed": true,
   "matchedRule": null,
   "group": [],
   "verificationStatus": "reported",
   "type": "unknown",
   "…": "1 more keys omitted here for length"
  },
  {
   "bot": "Bytedance",
   "matchToken": "Bytedance",
   "path": "/",
   "allowed": true,
   "matchedRule": null,
   "group": [],
   "verificationStatus": "unverified",
   "type": "unknown",
   "…": "1 more keys omitted here for length"
  },
  "… 2 more entries omitted here for length"
 ],
 "recommendations": [],
 "contentSignals": [],
 "catalogVersion": "2026-09-06-b3",
 "catalog": [
  {
   "label": "Baiduspider",
   "matchToken": "Baiduspider",
   "type": "search",
   "evidenceUrl": "https://raw.githubusercontent.com/monperrus/crawler-user-agents/master/crawler-user-agents.json",
   "verificationStatus": "reported",
   "source": "https://raw.githubusercontent.com/monperrus/crawler-user-agents/master/crawler-user-agents.json",
   "verified": false,
   "provenance": {
    "checkedAt": "2026-09-06",
    "kind": "third_party_catalog",
    "typeVerificationStatus": "reported",
    "note": "Observed/catalogued label; operator documentation and current purpose not independently confirmed."
   }
  },
  {
   "label": "Baidubot",
   "matchToken": "Baidubot",
   "type": "unknown",
   "evidenceUrl": null,
   "verificationStatus": "unverified",
   "source": "WAVE_B_PLAN.md §5 / WAVE_B_REVIEW.md candidate catalog",
   "verified": false,
   "provenance": {
    "checkedAt": "2026-09-06",
    "kind": "accepted_plan_candidate",
    "typeVerificationStatus": "unverified",
    "note": "Candidate spelling supplied by the accepted plan; existence and purpose are not verified. Formal matching is hypothetical."
   }
  },
  "… 4 more catalog entries omitted here for length"
 ]
}
```

### Other tools we built

### Formal audit scope

The crawler checker downloads only robots.txt and, when requested and permitted, llms.txt. It does not load the supplied website's homepage, fetch any of the test paths, render JavaScript or send traffic using a bot's identity. Paths are strings evaluated against a parsed robots document. The matrix is a static policy calculation with source evidence, not an experiment that observes bot behavior.

Supply website origins such as https://example.com without a page path or query. Put the paths to compare in the paths array. This separation makes request scope visible: adding ten paths increases local matrix calculations, not ten page downloads. The actor's own source requests use its declared ChinaMetadataAuditBot token and are not disguised as Baiduspider, Bytespider or another catalog entry.

A full site audit can be a payable result even when robots.txt and llms.txt both return 404. Those responses establish known absence at the checked time. In contrast, a 503, timeout, truncated response or HTML challenge does not establish that rules are absent. The corresponding matrix cells remain unknown and the site row is free partial.

### Catalog provenance and identity uncertainty

The actor ships twenty catalog candidates locally. Each entry separates label, matchToken, type, evidenceUrl, verificationStatus and provenance. A friendly product name is not automatically a confirmed robots product token. Some spellings come from the accepted plan and remain unverified. Others are reported by a public catalog or observed by a third-party measurement service; those are identified as reported rather than silently upgraded to official confirmation.

The accepted list contains Baiduspider, Baidubot, Bytespider, Bytedance, Doubao, DeepSeekBot, ChatGLM-Spider, Qwenbot, PanguBot, PetalBot, Kimi, Hunyuan, YiBot, SenseBot, iFlytekBot, MiniMaxBot, InternLMBot, 360Spider, Sogou web spider and Yisouspider. The inclusion of a name is coverage of a requested candidate, not proof that its operator publishes or currently uses that exact token.

A reported token can be evaluated against a robots file as a formal string. An unverified token is evaluated as a hypothetical product token, with that interpretation attached to each cell. This gives a site owner a transparent policy matrix without claiming that all twenty candidates are confirmed active AI crawlers. Preserve verificationStatus when you export or present the matrix.

The current catalog does not claim independently confirmed bot purposes. It therefore does not generate search-versus-training rule snippets from reported or unverified types. That restriction is intentional: recommending a training block for a token whose function is uncertain could mislead a site owner. The recommendations array can be empty even when the matrix contains useful policy observations.

Bytespider's behavior is handled as a report with a source and provenance, not as an `ignoresRobots:true` field. The cited research reports noncompliance in its own measurement setting. This build does not repeat that experiment on the buyer's site and does not convert the report into a universal prediction about every request. Formal robots permission and actual observed compliance remain separate questions.

### Robots group and path matching

Agent matching is case-insensitive for the catalog matchToken. Groups with the same matching token are combined, and the wildcard group is used when no specific token group matches. Multiple user-agent lines can share one group. A later specific group is not accidentally mixed with wildcard restrictions merely because both appear in the same document.

Path matching is case-sensitive and starts at the beginning of the requested path. The most specific matching rule is selected, with Allow winning when matching rule specificity is equal. The parser supports wildcard segments and an end anchor. A rule targeting a .pdf suffix does not automatically cover the same path with an extra query suffix when the end anchor requires the path to end there.

UTF-8 characters and percent-encoded octets are normalized for comparison. Unreserved encoded characters can be decoded, while an encoded reserved slash remains distinct from a literal path separator. This prevents a simplistic decode-everything implementation from changing which rule wins. The offline tests include Chinese path text, encoded forms, case differences, wildcard rules and ties.

An empty Disallow does not prohibit the entire site. A robots response containing no applicable rule allows the formal path under the parser's model. That result still depends on knowing the robots response: a missing file with a definite 404 can produce known allowed checks, while an unknown response cannot be converted into the same outcome.

The parser follows the rules exercised by the RFC fixtures in this build. It is a policy inspection tool, not an authentication mechanism. Robots is advisory and does not grant access rights. A server can also enforce WAF, authentication, rate limits or other controls that are outside these two text files; those controls are not tested by loading the homepage.

### Scores with explicit denominators

aiAccessScore is the allowed percentage among cells with a known boolean allowed value. aiAccessNumerator counts known allowed cells; aiAccessDenominator counts all known allowed or denied cells; aiAccessUnknown counts cells whose outcome could not be established. A denominator of zero yields null. Unknown never becomes a perfect score.

For example, a three-cell calculation with one allow, one deny and one unknown has numerator 1, denominator 2 and score 50. It does not have a score of 66.7 by treating unknown as allowed, and it does not have 33.3 by silently treating unknown as denied. The output retains the unknown count so that you can decide whether enough evidence exists for your own reporting threshold.

The matrix operates on selected token/path combinations. An allowed hypothetical candidate counts as a known formal rule calculation when the robots source is known; its token existence is still labelled unverified in the matrix. Do not turn that mathematical score into a claim that the same percentage of real Chinese AI traffic can access your website.

aiSearchScore is narrower: it uses only entries whose search purpose is confirmed. If the current catalog selection has no such entries, its denominator is zero and the score is null. This is preferable to calling every unknown-purpose bot a search crawler. The general access score can therefore be numeric while the search score remains null.

blockedBots lists catalog labels with at least one denied selected path. It does not mean the bot is blocked on every URL, blocked by the network edge, or absent from server logs. Use the matrix's matchedRule and group fields to understand the exact path decision before editing a robots file through your own authorized deployment process.

### llms.txt and content signals

When checkLlms is true, the actor first verifies that its own token is allowed to request /llms.txt. A robots denial prevents the request. That leaves llms content unknown and makes the requested audit partial. A successful text response establishes file presence, while 404 or 410 establishes absence. An HTML challenge or server error is not treated as a usable llms file.

File presence is the scope of the llms check. The actor does not promise that an LLM reads the file, respects it, indexes every listed link or produces a citation. Links contained in llms.txt are not followed. The checked file is a source observation that can support your own website-maintenance workflow, not a traffic guarantee.

Content-Signal lines are retained with the groups beside which they appeared. They are not automatically merged into the standardized Allow/Disallow decision and are not interpreted as permission to run a model over site content. Keep these nonstandard declarations as an additional policy surface when discussing access with your website team.

### Field reference

Every field in the overview view is listed here, including diagnostic and notice fields that may be absent from a complete domain row. A missing optional domain field after pre-work validation means no corresponding source observation was made.

#### `website`

Normalized buyer origin for the audit. No homepage was fetched; all path calculations belong to the robots and optional llms observations for this origin.

#### `aiAccessScore`

Allowed percentage among known formal matrix cells. Null when denominator is zero. It does not estimate the fraction of real bots or real traffic admitted by a server.

#### `aiAccessNumerator`

Number of known allowed token/path calculations. Compare to aiAccessDenominator, not the count of catalog brands or incoming bot requests.

#### `aiAccessDenominator`

Number of matrix cells with a boolean allowed result. Unknown source observations are excluded and reported separately so the percentage remains interpretable.

#### `aiAccessUnknown`

Count of cells whose source policy could not be established. A zero known denominator and a positive unknown count must remain an unknown score, never 100 percent.

#### `aiSearchScore`

Allowed percentage restricted to confirmed search-purpose entries. With no confirmed eligible entries the denominator is zero and this score is null.

#### `aiSearchNumerator`

Allowed known cells in the confirmed search subset. It is intentionally narrower than aiAccessNumerator and may be zero when the general matrix is populated.

#### `aiSearchDenominator`

Known cells for confirmed search-purpose tokens only. Reported or unverified purposes do not qualify simply because a label resembles a search product.

#### `aiSearchUnknown`

Unknown cells within the eligible confirmed search subset. An empty eligible subset is different from a fully measured denied subset; keep its denominator beside this value.

#### `robotsTxt`

Object with exists, statusCode and exact robots URL. Null existence indicates uncertainty; false with 404/410 is known absence, not an explicit publisher Allow statement.

#### `llmsTxt`

Presence/status object for the optional llms file. Disabled, not\_found, present and unknown remain distinct. Links inside the file are never followed.

#### `blockedBots`

Labels with at least one denied selected path. This does not mean every URL is denied or that a WAF actively blocks those bot connections.

#### `summary`

Human-readable count explanation for the formal audit or an empty-scope notice. Use numeric denominator fields for calculations rather than parsing this sentence.

#### `matrix`

One cell per selected bot and path, with allowed/null, matched rule, merged group and catalog provenance. Cells are local calculations, not HTTP page requests.

#### `recommendations`

Optional rule proposals only for confirmed search/training purposes. An empty array is expected when the catalog has no sufficiently confirmed types; no website is edited.

#### `contentSignals`

Nonstandard Content-Signal values retained with adjacent agent groups. They are evidence separate from standardized robots Allow/Disallow matching.

#### `catalogVersion`

Version of the bundled candidate catalog. Keep it with historical audits because catalog provenance or type confirmation can evolve independently of a website policy.

#### `catalog`

Selected bot records including evidenceUrl, verificationStatus and provenance. A requested candidate can be present while its token identity remains explicitly unverified.

#### `unprocessed`

Known units left unfinished under the run contract. It does not invent an exact count for source pages the actor never fetched. Read cap warnings for an uncounted tail.

#### `schemaVersion`

Stable row-contract version. Use it when validating a downstream parser; a version label alone does not establish cloud acceptance or a live pricing configuration.

#### `type`

Row category such as model, article, audit, contacts, source or notice. Filter by type together with found and partial to keep diagnostic records out of business-result tables.

#### `sourceUrl`

Primary source surface for the observation. It points to permitted API/feed/robots/HTML evidence and is not an instruction to crawl additional linked resources.

#### `found`

True only for a complete payable unit. False covers both clean absence and partial failure, so combine it with status, error and partial instead of using it alone.

#### `status`

Domain-specific classification such as found, no\_updates, no\_contacts, no\_data or partial. It conveys a more useful outcome than the platform run status alone.

#### `resultCount`

One on complete payable rows and zero on free rows. It counts this actor's billing unit, not nested objects, HTTP requests, tokens or discovered links.

#### `partial`

True when the row or run contract is incomplete. Useful partial evidence can remain in the dataset, but it is delivered without the result-found event.

#### `error`

Stable nonempty reason for a failed requested observation. Empty string is reserved for rows without a recorded error; it is never used to disguise unavailable sources.

#### `warnings`

Bounded interpretation or coverage notices. A warning does not automatically mean partial, so read the relevant domain contract and explicit partial flag.

#### `checkedAt`

UTC observation assembly time. It is distinct from source publication, creation or modification dates and should not replace unknown source timestamps.

#### `evidence`

Nested provenance describing the permitted source surface and minimal supporting fields or URLs. Retain it for review; it is not a permission certificate.

#### `confidence`

Categorical evidence description, not a calibrated probability. source\_metadata indicates the source contract was assembled, not that every downstream interpretation is correct.

#### `action`

A small operational hint always `review` for this Actor. It is descriptive output and never executes a browser action, sends a message or changes an external application.

### Configuration cookbook

These are configuration examples, not additional source captures. Each example starts from the exact prefill and changes the shown scope. The stated result contract describes how to assess a run; it does not promise a currently available source result.

#### Audit the two reviewed origins

The prefill inspects example.com and apify.com through their text policy files. It does not make a GET request to either homepage.

```json
{
 "sites": [
  "https://example.com",
  "https://apify.com"
 ],
 "paths": [
  "/"
 ],
 "bots": [
  "Baiduspider",
  "Baidubot",
  "Bytespider",
  "… 17 more tokens from the prefill list"
 ],
 "checkLlms": true,
 "maxItems": 2
}
```

Check robotsTxt and llmsTxt status values first, then inspect the matrix and its denominator. A 404 file can still be a complete audit.

Budget reference for this configuration: at most 2 payable units under the result limit, or $0.045 in planned start-plus-result events if that many complete units are delivered. This is a ceiling calculation for the configured limit, not a forecast of source yield.

#### Audit only one reviewed origin

This is a simple one-site policy check. The existence of a missing robots file is still useful known evidence and can produce a payable formal audit.

```json
{
 "sites": [
  "https://example.com"
 ],
 "paths": [
  "/"
 ],
 "bots": [
  "Baiduspider",
  "Baidubot",
  "Bytespider",
  "… 17 more tokens from the prefill list"
 ],
 "checkLlms": true,
 "maxItems": 1
}
```

Do not interpret a perfect formal score as evidence that a server accepts every bot connection. No live bot traffic is simulated.

Budget reference for this configuration: at most 1 payable units under the result limit, or $0.025 in planned start-plus-result events if that many complete units are delivered. This is a ceiling calculation for the configured limit, not a forecast of source yield.

#### Compare public and private paths

Adding paths expands local calculations only. The actor does not request those paths, even when a rule would allow them.

```json
{
 "sites": [
  "https://example.com"
 ],
 "paths": [
  "/",
  "/private",
  "/private/public"
 ],
 "bots": [
  "Baiduspider",
  "Baidubot",
  "Bytespider",
  "… 17 more tokens from the prefill list"
 ],
 "checkLlms": true,
 "maxItems": 2
}
```

Use matchedRule and group on each cell to understand a denial or more specific exception. Avoid reducing a path-specific policy to one universal blocked flag.

Budget reference for this configuration: at most 2 payable units under the result limit, or $0.045 in planned start-plus-result events if that many complete units are delivered. This is a ceiling calculation for the configured limit, not a forecast of source yield.

#### Inspect one reported crawler token

A smaller bot selection makes a targeted configuration review easier. Its reported catalog provenance is preserved; the actor does not query Baidu.

```json
{
 "sites": [
  "https://example.com",
  "https://apify.com"
 ],
 "paths": [
  "/"
 ],
 "bots": [
  "Baiduspider"
 ],
 "checkLlms": true,
 "maxItems": 2
}
```

A matching robots group is a formal string observation. It does not independently authenticate the operator of any request carrying that token.

Budget reference for this configuration: at most 2 payable units under the result limit, or $0.045 in planned start-plus-result events if that many complete units are delivered. This is a ceiling calculation for the configured limit, not a forecast of source yield.

#### Inspect Bytespider formal policy

This uses the catalog token for policy matching and includes a sourced behavior report in the catalog metadata. It does not reproduce that research on your website.

```json
{
 "sites": [
  "https://example.com",
  "https://apify.com"
 ],
 "paths": [
  "/"
 ],
 "bots": [
  "Bytespider"
 ],
 "checkLlms": true,
 "maxItems": 2
}
```

Keep robots permission separate from reported compliance. The output contains no universal ignoresRobots true assertion.

Budget reference for this configuration: at most 2 payable units under the result limit, or $0.045 in planned start-plus-result events if that many complete units are delivered. This is a ceiling calculation for the configured limit, not a forecast of source yield.

#### Include hypothetical emerging tokens

These plan candidates remain unverified where official token evidence is unavailable. The matrix labels their evaluation as hypothetical product-token matching.

```json
{
 "sites": [
  "https://example.com",
  "https://apify.com"
 ],
 "paths": [
  "/"
 ],
 "bots": [
  "DeepSeekBot",
  "Qwenbot",
  "Doubao"
 ],
 "checkLlms": true,
 "maxItems": 2
}
```

A result can still explain how the supplied robots file treats those strings. Do not market the rows as three confirmed active crawlers.

Budget reference for this configuration: at most 2 payable units under the result limit, or $0.045 in planned start-plus-result events if that many complete units are delivered. This is a ceiling calculation for the configured limit, not a forecast of source yield.

#### Skip llms file presence

Choose this when the requested contract is only robots policy. llms status is disabled, and a missing llms observation is not an error for this scope.

```json
{
 "sites": [
  "https://example.com",
  "https://apify.com"
 ],
 "paths": [
  "/"
 ],
 "bots": [
  "Baiduspider",
  "Baidubot",
  "Bytespider",
  "… 17 more tokens from the prefill list"
 ],
 "checkLlms": false,
 "maxItems": 2
}
```

The actor does not silently disable llms after a failure when the option was true. A requested but unavailable llms check is partial.

Budget reference for this configuration: at most 2 payable units under the result limit, or $0.045 in planned start-plus-result events if that many complete units are delivered. This is a ceiling calculation for the configured limit, not a forecast of source yield.

#### Evaluate an encoded Chinese path

The comparison normalizes UTF-8 and percent octets according to the parser rules. Both strings are evaluated locally against the same source policy.

```json
{
 "sites": [
  "https://example.com",
  "https://apify.com"
 ],
 "paths": [
  "/%E4%B8%AD%E5%9B%BD",
  "/中国"
 ],
 "bots": [
  "Baiduspider",
  "Baidubot",
  "Bytespider",
  "… 17 more tokens from the prefill list"
 ],
 "checkLlms": true,
 "maxItems": 2
}
```

Compare matched rules rather than assuming literal string equality. Encoded reserved slashes remain distinct from path separators.

Budget reference for this configuration: at most 2 payable units under the result limit, or $0.045 in planned start-plus-result events if that many complete units are delivered. This is a ceiling calculation for the configured limit, not a forecast of source yield.

#### Check suffix and query rules locally

An end-anchored robots rule may distinguish these path strings. Neither URL is fetched by this actor, so query text here is only matrix input.

```json
{
 "sites": [
  "https://example.com",
  "https://apify.com"
 ],
 "paths": [
  "/document.pdf",
  "/document.pdf?download=1"
 ],
 "bots": [
  "Baiduspider",
  "Baidubot",
  "Bytespider",
  "… 17 more tokens from the prefill list"
 ],
 "checkLlms": true,
 "maxItems": 2
}
```

Use these cells to review wildcard and dollar-anchor policy effects. They do not test whether a download endpoint exists or returns a file.

Budget reference for this configuration: at most 2 payable units under the result limit, or $0.045 in planned start-plus-result events if that many complete units are delivered. This is a ceiling calculation for the configured limit, not a forecast of source yield.

#### Bound a larger origin queue

Only the first configured site is processed when the site cap is one. The remaining site is counted as unprocessed rather than reported as audited.

```json
{
 "sites": [
  "https://example.com",
  "https://apify.com"
 ],
 "paths": [
  "/"
 ],
 "bots": [
  "Baiduspider",
  "Baidubot",
  "Bytespider",
  "… 17 more tokens from the prefill list"
 ],
 "checkLlms": true,
 "maxItems": 1
}
```

A free notice explains the working cap. Increasing maxItems changes coverage, while the buyer budget still independently limits payable delivery.

Budget reference for this configuration: at most 1 payable units under the result limit, or $0.025 in planned start-plus-result events if that many complete units are delivered. This is a ceiling calculation for the configured limit, not a forecast of source yield.

#### Review case-sensitive path rules

Robots agent matching is case-insensitive, while paths are case-sensitive. This pair helps inspect that distinction without requesting either administration path.

```json
{
 "sites": [
  "https://example.com",
  "https://apify.com"
 ],
 "paths": [
  "/Admin",
  "/admin"
 ],
 "bots": [
  "Baiduspider",
  "Baidubot",
  "Bytespider",
  "… 17 more tokens from the prefill list"
 ],
 "checkLlms": true,
 "maxItems": 2
}
```

A difference in the matrix is not a login attempt or an assertion that either path is publicly accessible through the web server.

Budget reference for this configuration: at most 2 payable units under the result limit, or $0.045 in planned start-plus-result events if that many complete units are delivered. This is a ceiling calculation for the configured limit, not a forecast of source yield.

#### Exercise an empty site scope

The actor can return a clean free no\_data row for no supplied sites. This is a useful downstream absence test and contains no fabricated matrix.

```json
{
 "sites": [],
 "paths": [
  "/"
 ],
 "bots": [
  "Baiduspider",
  "Baidubot",
  "Bytespider",
  "… 17 more tokens from the prefill list"
 ],
 "checkLlms": true,
 "maxItems": 2
}
```

Use a separate unavailable-robots fixture to verify null scores and partial status. Empty input and failed source access are different cases.

Budget reference for this configuration: at most 2 payable units under the result limit, or $0.045 in planned start-plus-result events if that many complete units are delivered. This is a ceiling calculation for the configured limit, not a forecast of source yield.

![Result and billing evidence](assets/readme-evidence.svg)

### Recorded platform runs (accepted acceptance runs)

The records below are exact; only `checkedAt` differs between repeated runs.

#### Happy path

Run `1OgbI79U4RmBr3GUh` on build 0.1.2, 2026-09-06, 1 s, Dataset records: 1, charged events: `{"apify-actor-start": 1, "result-found": 1}`. The exact first paid record is shown in the Output section above.

Input:

```json
{
 "sites": [
  "https://example.com"
 ],
 "checkLlms": true,
 "maxItems": 2
}
```

#### Correct empty-input record

Run `9gIm0JphkII7TnT1b` on build 0.1.2, 2026-09-06, 2 s, Dataset records: 1, charged events: `{"apify-actor-start": 1, "result-found": 0}`.

```json
{
 "schemaVersion": "1.0",
 "type": "no_data",
 "sourceUrl": null,
 "found": false,
 "status": "no_data",
 "resultCount": 0,
 "partial": false,
 "error": "",
 "warnings": [],
 "checkedAt": "2026-09-06T06:37:52.098Z",
 "evidence": null,
 "confidence": null,
 "action": "review",
 "summary": "No sites supplied."
}
```

#### Unreachable source record

Run `J7iitCcpXG8wCJsh3` on build 0.1.2, 2026-09-06, 2 s, Dataset records: 1, charged events: `{"apify-actor-start": 1, "result-found": 0}`. The source could not be reached; the record is free and carries the reason.

```json
{
 "schemaVersion": "1.0",
 "type": "audit",
 "sourceUrl": "https://nonexistent-source-zzq.example/robots.txt",
 "found": false,
 "status": "partial",
 "resultCount": 0,
 "partial": true,
 "error": "network_error",
 "warnings": [
  "formal_rules_do_not_guarantee_behavior",
  "catalog_contains_unconfirmed_tokens"
 ],
 "checkedAt": "2026-09-06T06:37:54.864Z",
 "evidence": {
  "kind": "robots_and_llms_metadata",
  "robotsUrl": "https://nonexistent-source-zzq.example/robots.txt"
 },
 "confidence": null,
 "action": "review",
 "website": "https://nonexistent-source-zzq.example",
 "aiAccessScore": null,
 "aiAccessNumerator": 0,
 "aiAccessDenominator": 0,
 "aiAccessUnknown": 20,
 "aiSearchScore": null,
 "aiSearchNumerator": 0,
 "aiSearchDenominator": 0,
 "aiSearchUnknown": 0,
 "robotsTxt": {
  "exists": null,
  "statusCode": null,
  "url": "https://nonexistent-source-zzq.example/robots.txt"
 },
 "llmsTxt": {
  "exists": null,
  "statusCode": null,
  "url": "https://nonexistent-source-zzq.example/llms.txt",
  "status": "unknown"
 },
 "blockedBots": [],
 "summary": "0/0 known formal path checks allowed; 20 unknown. Bot existence and traffic are separate observations.",
 "recommendations": [],
 "contentSignals": [],
 "catalogVersion": "2026-09-06-b3",
 "…": "catalog and matrix omitted here for length; same structure as the Output record"
}
```

#### Prefill run on the two reviewed origins (example.com and apify.com)

Run `oyN9aRRLAmV4L7wYI` on build 0.1.2, 2026-09-06, 9 s, Dataset records: 2, charged events: `{"apify-actor-start": 1, "result-found": 2}`. 2 paid record(s).

Input:

```json
{
 "sites": [
  "https://example.com",
  "https://apify.com"
 ],
 "paths": [
  "/"
 ],
 "bots": [
  "Baiduspider",
  "Baidubot",
  "Bytespider",
  "Bytedance",
  "Doubao",
  "… 15 more entries omitted here for length"
 ],
 "checkLlms": true,
 "maxItems": 2
}
```

The two paid records have the same shape as the Output record above (one per origin); they are omitted here for length.

### Reading a run before using its data

Open both the dataset and the OUTPUT record. They answer different questions. The dataset contains observations and explanations that can be inspected one row at a time. OUTPUT records how much work was requested, processed, delivered, charged, left unfinished, or affected by a failure. A nonempty dataset is not a promise that every supplied input succeeded. Keep the run identifier next to exports so that an individual row can be traced back to the run that produced it.

For business use, begin with `found === true`, `partial === false`, `error === ""` and `resultCount === 1`. Those fields form the complete-result contract. A row that has useful-looking source values but also `partial:true` is supporting evidence for investigation. It must not silently enter the same downstream table as a complete result. If you need a single export, keep the flags as columns and use a saved filter; do not discard the flags during CSV conversion.

An empty string in `error` has a specific meaning: the actor did not record an error for that row. It is different from an absent field, a null source measurement, an empty array of discoveries, and a run that stopped before it reached the source. A successful absence carries `found:false`, `resultCount:0`, and `error:""`. An unavailable source carries a reason and partial status. This distinction allows an alerting system to separate “nothing to report” from “the check needs attention.”

`checkedAt` is the time the actor assembled the observation. It does not replace the source's own date, establish when a model was marketed, establish when a journalist first published a story, or establish the age of a phone number. Preserve original source dates in their own columns. When comparing runs, use UTC timestamps or convert both sides to the same timezone before applying a business-day grouping.

`confidence` is a categorical description of the evidence boundary. It is not a calibrated probability. A value such as `source_metadata` means that a complete contract was assembled from the permitted source surface. It cannot be interpreted as a percentage likelihood of legal permission, business relevance, future reachability, caller identity, or an upstream provider's continued availability.

`warnings` can coexist with a complete result when the warning describes interpretation rather than a missing required observation. For example, catalog uncertainty is different from a failed robots request. Read warning values together with the actor-specific contract below. A partial row is always free of the result event, even when its content contains details that would have been useful in a successful check.

### Delivery, budget and replay

The actor uses one result event, `result-found`, for each complete payable unit. The dataset row and result event are delivered through the SDK's atomic `pushData` interface. There is no separate application-level charge followed by an unrelated dataset write. Free explanation rows use the same dataset without a result event name. The platform's automatic run-start event is outside those row decisions.

Before a payable row is delivered, the actor reads the active pricing information and the buyer's remaining run budget. Paid deliveries are serialized through a mutex so that two callers cannot both spend the same remainder. The final comparison is made inside that critical section at microdollar precision. If the remainder cannot pay for the complete event, delivery stops and the remaining work is identified in OUTPUT when known.

An unknown budget is not treated as an unlimited budget. If the charging manager cannot return a valid budget, the actor logs a stable error and fails the run. It also refuses a pricing configuration that charges for automatic dataset items: that would make ordinary free diagnostics billable. Such a pricing problem may therefore yield no dataset rows; the authoritative explanation is the failed run and log, not a paid error record.

The guard checks SDK charge confirmation only when pricing is monetized. Local development with unmonetized SDK settings can return a zero charged count by design, so that signal is not interpreted as a buyer budget failure. In a monetized run, a missing or contradictory charge confirmation is uncertain delivery. The actor stops, records `deliveryUncertain`, and fails rather than retrying the same paid push.

A last successful row may legitimately be delivered with the event limit reached. That row is counted before the actor stops. If your budget was intended to cover exactly a small number of results, seeing that final row and a budget-exhausted flag is consistent. Compare paid counts and unprocessed counts before assuming that an extra row was charged or a result was lost.

Do not automatically replay a failed delivery. Inspect the dataset, OUTPUT and the platform charge log first. A transport failure can happen after some of the underlying operation has already happened. This build has no exactly-once ledger or cross-run transaction coordinator. `replaySafe:false` is deliberate: an operator needs to reconcile uncertain delivery before deciding what to repeat.

### Network boundaries and operating limits

All source requests use HTTPS to public hosts. The runtime rejects credentials embedded in URLs, fragments, nonstandard ports, private or loopback addresses, cloud metadata destinations, mapped IPv6, and prohibited platform domains. It resolves the hostname before connecting, checks every returned address, and pins the connection to the addresses that passed that check. A public-looking hostname is not enough to pass the guard.

Redirects are handled manually. Each new target must pass the URL and address checks again; applicable actor-specific origin and path restrictions are also enforced. The source reader allows at most five redirect hops. An allowed first URL does not grant permission to follow an arbitrary redirect, carry a credential to a new host, or load a login page.
The source reader has a twenty-second ceiling covering DNS, connection and body reading. API, feed and HTML responses are limited to 2 MiB each, robots to 512 KiB and llms to 256 KiB. The run also has a 50 MiB response-byte ceiling and a working deadline of 240 seconds inside the 300-second platform timeout. These limits are ceilings, not targets and not an assurance that a remote site will respond quickly.

Retries apply to transient network failures, HTTP 429 and server errors. Invalid JSON, bad XML, an unsuitable content type, a blocked destination, a refused redirect or a truncated body is not made trustworthy by repeating it. Retry-After is bounded by the working deadline. Every source attempt remains subject to the actor's run-wide request ceiling.

The actor treats returned text as data. It does not run page JavaScript, execute code from repositories, load image resources, submit a form, log into an account, open a messaging application or dereference a social link found in a source. XML external entities and DTDs are rejected by the feed reader. These boundaries reduce the surface of the job and keep the output tied to the advertised source surface.

Source availability can vary by geography, hosting network and time. A fixture test proves code behavior for the recorded response shape; it does not prove that every production host is reachable today. The accepted planning evidence includes separate datacenter observations. Cloud acceptance of this draft is a separate step and should be recorded with the actual run ID after the orchestrator performs it.

### Export and integration notes

JSON is the best first export because it preserves nulls, booleans, arrays and nested evidence objects. CSV and Excel are useful for reviewing scalar fields, but nested arrays may appear as serialized JSON. Keep the JSON export if you intend to build a normalized relational table. A blank spreadsheet cell can lose the distinction between an unknown value and a deliberately empty string.

When flattening results, use the row's stable domain key and the run identifier together. Child objects such as evidence fragments or matrix cells belong to that parent result. Avoid turning each child into a separately billable unit in your own reports unless that is a clearly documented downstream convention. The actor's billing unit is defined in the Pricing section and does not change when you reshape its JSON.

A scheduled run can be connected to a dataset export, an API consumer or your own webhook integration through Apify's normal platform features. This actor does not itself create schedules, send messages, change a remote website, publish a listing or update a CRM. Test your downstream transformation against complete, absence and partial rows before attaching it to an unattended business workflow.

Use a small scope first and inspect its output. Increase one limit at a time so that changes in coverage have an explanation. A larger input array can increase request work even when the payable-result cap is small. Review both the actor-specific source ceiling and the budget ceiling, because they protect different things. A budget limits paid delivery; it does not replace a source rate or response-size limit.

### Troubleshooting by evidence

**The run succeeded but returned an error row.** A handled source problem is represented as free diagnostic data so that the daily check stays inspectable. Read `partial`, `error`, `warnings` and OUTPUT rather than relying on run status alone. The run is failed when the actor cannot safely reason about money or persistent state; ordinary source failures can be contained and reported without failing unrelated complete work.

**A source is reachable in a browser but the actor returns partial.** Inspect whether the browser used an existing session, executed JavaScript, followed a cross-origin redirect or displayed an HTML challenge. The actor uses the documented unauthenticated source surface and validates the response type. A browser screenshot of a useful page does not show that the same permitted machine-readable response was available to the actor.

**Fewer paid rows appeared than the requested maximum.** The maximum is a ceiling. Filtering, deduplication, absence, unknown source data, the working deadline, a source cap or a buyer budget can all reduce delivered complete rows. OUTPUT identifies measurable unprocessed work; source pagination may also leave an uncounted tail that is reported as a cap warning rather than an invented exact count.

**A field contains null.** Read the field's definition before substituting zero. Null preserves lack of evidence. Zero is a measurement or count and can materially alter a chart, a score or an automated decision. If your destination system cannot represent null, keep a companion status column that explains the substitution. Do not silently transform unknown observations into favorable outcomes.

**A source changed its response structure.** Keep the relevant source URL, run ID, actor version, status flags and a minimal redacted excerpt when opening an issue. A useful bug report explains which expected field was missing and how the row was classified. Do not include API keys, private account information or unnecessary personal contact details in a public issue.

**Can the build be treated as cloud accepted?** The private build named in the evidence banner passed the acceptance runs listed under Recorded platform runs; publication to the Store is a separate step.

### Support and responsibility

Use the actor's issue page for a reproducible defect or a request for a new response shape. Include the input settings with secrets removed, the run ID where available, the affected field and whether the problem is complete absence, partial source failure or uncertain delivery. A short reproducible example is more useful than an unfiltered export containing unrelated data.

The buyer supplies the scope and must have an appropriate basis for processing and retaining it. Public reachability and a robots rule are different from permission to republish content or contact a person. Apply your organization's retention, access and data-protection rules, including applicable PIPL and GDPR obligations where relevant. This tool reports technical evidence within its contract; it does not issue a legal clearance.

### Compact Chinese guide / 中文说明

本工具仅处理输入中指定的公开来源，输出包含完整结果、无结果和部分失败三种不同情况。请同时查看 `found`、`partial`、`error` 和 OUTPUT，不要把未知值 `null` 改成零或百分之百。完整结果按 result-found 事件计费，错误和说明行不收取结果事件费；启动费仍可能产生。

仅请求 robots.txt 和 llms.txt，不请求首页或测试路径。机器人目录包含 reported/unverified 候选名称；分数是已知规则检查中的允许比例，不代表真实流量保证。

#### Related tools

Related tools for adjacent workflows in AI and search visibility.

| Actor | What it does |
|---|---|
| [AI Crawler Access Checker](https://apify.com/zinin/ai-crawler-access-checker) | Pair it in the AI and search visibility workflow: Audit up to 100 sites for 16 AI crawler policies |
| [llms.txt Auditor & AI Crawler Policy Checker](https://apify.com/zinin/llms-txt-auditor) | Pair it in the AI and search visibility workflow: Audit public llms.txt, llms-full.txt, and root robots.txt rules for nine named AI crawlers |
| [AI Answer & Citation Change Monitor](https://apify.com/zinin/ai-answer-change-alert) | Pair it in the AI and search visibility workflow: Monitor grounded AI answers by query, model, and language; detect rewrites and cited-domain additions or... |
| [AI Overview Citation Tracker](https://apify.com/zinin/ai-overview-tracker) | Pair it in the AI and search visibility workflow: Track which public URLs and domains selected grounded AI models cite for buyer-supplied queries |
| [Domain Health Checker](https://apify.com/zinin/domain-health-checker) | Pair it in the AI and search visibility workflow: Audit DNS resolution, MX, SPF, DMARC, name servers, and TLS for a list of domains |

# Actor input Schema

## `sites` (type: `array`):

Buyer website origins. HTTPS public hosts only, no path or query. The website homepage is never downloaded.

## `paths` (type: `array`):

Paths for formal matching. Up to 10 paths of 500 characters; these paths are evaluated locally and never fetched.

## `bots` (type: `array`):

Catalog labels. Choose from the 20 actor-local candidates; provenance distinguishes reported and unverified tokens.

## `checkLlms` (type: `boolean`):

Check llms.txt. Fetch only after robots allows our llms path; missing 404 is known absence, failures are unknown.

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

Maximum sites. At most 50; sites times paths times bots must not exceed 10000.

## Actor input object example

```json
{
  "sites": [
    "https://example.com",
    "https://apify.com"
  ],
  "paths": [
    "/"
  ],
  "bots": [
    "Baiduspider",
    "Baidubot",
    "Bytespider",
    "Bytedance",
    "Doubao",
    "DeepSeekBot",
    "ChatGLM-Spider",
    "Qwenbot",
    "PanguBot",
    "PetalBot",
    "Kimi",
    "Hunyuan",
    "YiBot",
    "SenseBot",
    "iFlytekBot",
    "MiniMaxBot",
    "InternLMBot",
    "360Spider",
    "Sogou web spider",
    "Yisouspider"
  ],
  "checkLlms": true,
  "maxItems": 2
}
```

# Actor output Schema

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

No description

## `summary` (type: `string`):

Fields: requested, processed, unprocessed, delivered, paid, free, failed, partial, fatal, deliveryUncertain, budgetExhausted, replaySafe, replayNote, schemaVersion, checkedAt, matrixChecks, catalogVersion, httpAttempts, logicalGets, responseBytes

# 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 = {
    "sites": [
        "https://example.com",
        "https://apify.com"
    ],
    "paths": [
        "/"
    ],
    "bots": [
        "Baiduspider",
        "Baidubot",
        "Bytespider",
        "Bytedance",
        "Doubao",
        "DeepSeekBot",
        "ChatGLM-Spider",
        "Qwenbot",
        "PanguBot",
        "PetalBot",
        "Kimi",
        "Hunyuan",
        "YiBot",
        "SenseBot",
        "iFlytekBot",
        "MiniMaxBot",
        "InternLMBot",
        "360Spider",
        "Sogou web spider",
        "Yisouspider"
    ],
    "checkLlms": true,
    "maxItems": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("zinin/chinese-ai-crawler-access-checker").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 = {
    "sites": [
        "https://example.com",
        "https://apify.com",
    ],
    "paths": ["/"],
    "bots": [
        "Baiduspider",
        "Baidubot",
        "Bytespider",
        "Bytedance",
        "Doubao",
        "DeepSeekBot",
        "ChatGLM-Spider",
        "Qwenbot",
        "PanguBot",
        "PetalBot",
        "Kimi",
        "Hunyuan",
        "YiBot",
        "SenseBot",
        "iFlytekBot",
        "MiniMaxBot",
        "InternLMBot",
        "360Spider",
        "Sogou web spider",
        "Yisouspider",
    ],
    "checkLlms": True,
    "maxItems": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("zinin/chinese-ai-crawler-access-checker").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 '{
  "sites": [
    "https://example.com",
    "https://apify.com"
  ],
  "paths": [
    "/"
  ],
  "bots": [
    "Baiduspider",
    "Baidubot",
    "Bytespider",
    "Bytedance",
    "Doubao",
    "DeepSeekBot",
    "ChatGLM-Spider",
    "Qwenbot",
    "PanguBot",
    "PetalBot",
    "Kimi",
    "Hunyuan",
    "YiBot",
    "SenseBot",
    "iFlytekBot",
    "MiniMaxBot",
    "InternLMBot",
    "360Spider",
    "Sogou web spider",
    "Yisouspider"
  ],
  "checkLlms": true,
  "maxItems": 2
}' |
apify call zinin/chinese-ai-crawler-access-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,zinin/chinese-ai-crawler-access-checker"
        }
    }
}
```

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/5HNZWFVbbdEJKfmBG/builds/YtPVXjlQ8UyLFEA6Q/openapi.json
