1# Apify Actors Development Guide
2
3Important: Before you begin, fill in the `generatedBy` property in the meta section of `.actor/actor.json`. Replace it with the tool and model you're currently using, such as "Claude Code with Claude Sonnet 4.5". This helps Apify monitor and improve AGENTS.md for specific AI tools and models.
4
5## What are Apify Actors?
6
7- Actors are serverless programs that run in the cloud. They're inspired by the UNIX philosophy - programs that do one thing well and can be easily combined to build complex systems.
8- Actors are programs packaged as Docker images that run in isolated containers
9
10## Core Concepts
11
12- Accept well-defined JSON input
13- Perform isolated tasks (web scraping, automation, data processing)
14- Produce structured JSON output to datasets and/or store data in key-value stores
15- Can run from seconds to hours or even indefinitely
16- Persist state and can be restarted
17
18## Do
19
20- accept well-defined JSON input and produce structured JSON output
21- use Apify SDK (`apify`) for code running ON Apify platform
22- validate input early with proper error handling and fail gracefully
23- use CheerioCrawler for static HTML content (10x faster than browsers)
24- use PlaywrightCrawler only for JavaScript-heavy sites and dynamic content
25- use router pattern (createCheerioRouter/createPlaywrightRouter) for complex crawls
26- implement retry strategies with exponential backoff for failed requests
27- use proper concurrency settings (HTTP: 10-50, Browser: 1-5)
28- set sensible defaults in `.actor/input_schema.json` for all optional fields
29- set up output schema in `.actor/output_schema.json`
30- clean and validate data before pushing to dataset
31- use semantic CSS selectors and fallback strategies for missing elements
32- respect robots.txt, ToS, and implement rate limiting with delays
33- check which tools (cheerio/playwright/crawlee) are installed before applying guidance
34- use `apify/log` package for logging (censors sensitive data)
35- implement readiness probe handler for standby Actors
36- handle the `aborting` event to gracefully shut down when Actor is stopped
37
38## Don't
39
40- do not rely on `Dataset.getInfo()` for final counts on Cloud platform
41- do not use browser crawlers when HTTP/Cheerio works (massive performance gains with HTTP)
42- do not hard code values that should be in input schema or environment variables
43- do not skip input validation or error handling
44- do not overload servers - use appropriate concurrency and delays
45- do not scrape prohibited content or ignore Terms of Service
46- do not store personal/sensitive data unless explicitly permitted
47- do not use deprecated options like `requestHandlerTimeoutMillis` on CheerioCrawler (v3.x)
48- do not use `additionalHttpHeaders` - use `preNavigationHooks` instead
49- do not assume that local storage is persistent or automatically synced to Apify Console - when running locally with `apify run`, the `storage/` directory is local-only and is NOT pushed to the Cloud
50- do not disable standby mode (`usesStandbyMode: false`) without explicit permission
51
52## Logging
53
54- **ALWAYS use the `apify/log` package for logging** - This package contains critical security logic including censoring sensitive data (Apify tokens, API keys, credentials) to prevent accidental exposure in logs
55
56### Available Log Levels in `apify/log`
57
58The Apify log package provides the following methods for logging:
59
60- `log.debug()` - Debug level logs (detailed diagnostic information)
61- `log.info()` - Info level logs (general informational messages)
62- `log.warning()` - Warning level logs (warning messages for potentially problematic situations)
63- `log.warningOnce()` - Warning level logs (same warning message logged only once)
64- `log.error()` - Error level logs (error messages for failures)
65- `log.exception()` - Exception level logs (for exceptions with stack traces)
66- `log.perf()` - Performance level logs (performance metrics and timing information)
67- `log.deprecated()` - Deprecation level logs (warnings about deprecated code)
68- `log.softFail()` - Soft failure logs (non-critical failures that don't stop execution, e.g., input validation errors, skipped items)
69- `log.internal()` - Internal level logs (internal/system messages)
70
71**Best practices:**
72
73- Use `log.debug()` for detailed operation-level diagnostics (inside functions)
74- Use `log.info()` for general informational messages (API requests, successful operations)
75- Use `log.warning()` for potentially problematic situations (validation failures, unexpected states)
76- Use `log.error()` for actual errors and failures
77- Use `log.exception()` for caught exceptions with stack traces
78
79## Graceful Abort Handling
80
81Handle the `aborting` event to terminate the Actor quickly when stopped by user or platform, minimizing costs especially for PPU/PPE+U billing.
82
83```typescript
84import { setTimeout } from 'node:timers/promises';
85
86Actor.on('aborting', async () => {
87 // Persist any state, do any cleanup you need, and terminate the Actor using `await Actor.exit()` explicitly as soon as possible
88 // This will help ensure that the Actor is doing best effort to honor any potential limits on costs of a single run set by the user
89 // Wait 1 second to allow Crawlee/SDK useState and other state persistence operations to complete
90 // This is a temporary workaround until SDK implements proper state persistence in the aborting event
91 await setTimeout(1000);
92 await Actor.exit();
93});
94```
95
96## Standby Mode
97
98- **NEVER disable standby mode (`usesStandbyMode: false`) in `.actor/actor.json` without explicit permission** - Actor Standby mode solves this problem by letting you have the Actor ready in the background, waiting for the incoming HTTP requests. In a sense, the Actor behaves like a real-time web server or standard API server instead of running the logic once to process everything in batch. Always keep `usesStandbyMode: true` unless there is a specific documented reason to disable it
99- **ALWAYS implement readiness probe handler for standby Actors** - Handle the `x-apify-container-server-readiness-probe` header at GET / endpoint to ensure proper Actor lifecycle management
100
101You can recognize a standby Actor by checking the `usesStandbyMode` property in `.actor/actor.json`. Only implement the readiness probe if this property is set to `true`.
102
103### Readiness Probe Implementation Example
104
105```typescript
106// Apify standby readiness probe at root path
107app.get('/', (req: Request, res: Response) => {
108 res.writeHead(200, { 'Content-Type': 'text/plain' });
109 if (req.headers['x-apify-container-server-readiness-probe']) {
110 res.end('Readiness probe OK\n');
111 } else {
112 res.end('Actor is ready\n');
113 }
114});
115```
116
117Key points:
118
119- Detect the `x-apify-container-server-readiness-probe` header in incoming requests
120- Respond with HTTP 200 status code for both readiness probe and normal requests
121- This enables proper Actor lifecycle management in standby mode
122
123## Commands
124
125```bash
126# Bootstrap & local development
127apify create [name] # Create new Actor project from a template
128apify init # Initialize Actor in current directory
129apify run # Run Actor locally with simulated platform env
130apify run --purge # Run after clearing previous local storage
131apify validate-schema # Validate .actor/input_schema.json
132
133# Authentication & account
134apify login # Authenticate account (token stored in ~/.apify)
135apify logout # Remove stored credentials
136apify info # Print currently authenticated account info
137
138# Deployment & remote execution
139apify push # Deploy Actor to platform per .actor/actor.json
140apify pull <actor> # Download Actor code from the platform
141apify call <actor> # Execute Actor remotely on the platform
142apify actors build <actor> # Create a new build of an Actor
143apify runs ls # List recent runs
144
145# Discovery (search Apify Store for community Actors)
146apify actors search "<query>" --user-agent <your-agent-name>
147apify actors info <actor> # Details about a specific Actor
148
149# Secrets (referenced from actor.json via "@mySecret")
150apify secrets add <name> <value> # Store a secret locally; uploaded on push
151apify secrets ls # List stored secret keys
152
153# TypeScript-specific helpers
154apify actor generate-schema-types # Generate TypeScript types from Actor schemas
155
156# Direct API access
157apify api <endpoint> # Authenticated HTTP request to Apify API
158
159# Help
160apify help # List all commands
161apify <command> --help # Detailed help for a specific command
162```
163
164Note: If no dedicated Actor exists for your target, search Apify Store for community options with `apify actors search "<query>" --user-agent <your-agent-name>` before building from scratch.
165
166Tip: Inside a running Actor, prefer the SDK (`Actor.getInput()`, `Actor.pushData()`, `Actor.setValue()`) over the equivalent `apify actor` runtime subcommands.
167
168## Apify Platform Environment
169
170When the Actor runs on the Apify platform, the API token is automatically available via the `APIFY_TOKEN` environment variable (note: the variable is `APIFY_TOKEN`, not `APIFY_API_TOKEN`). The Apify SDK reads it automatically, so you do not need to pass it explicitly. Locally, run `apify login` once and the SDK will use your stored credentials.
171
172## Safety and Permissions
173
174Allowed without prompt:
175
176- read files with `Actor.getValue()`
177- push data with `Actor.pushData()`
178- set values with `Actor.setValue()`
179- enqueue requests to RequestQueue
180- run locally with `apify run`
181
182Ask first:
183
184- npm/pip package installations
185- apify push (deployment to cloud)
186- proxy configuration changes (requires paid plan)
187- Dockerfile changes affecting builds
188- deleting datasets or key-value stores
189
190## Project Structure
191
192.actor/
193├── actor.json # Actor config: name, version, env vars, runtime settings
194├── input_schema.json # Input validation & Console form definition
195└── output_schema.json # Specifies where an Actor stores its output
196src/
197└── main.js # Actor entry point and orchestrator
198storage/ # Local-only storage for development (NOT synced to Cloud)
199├── datasets/ # Output items (JSON objects)
200├── key_value_stores/ # Files, config, INPUT
201└── request_queues/ # Pending crawl requests
202Dockerfile # Container image definition
203AGENTS.md # AI agent instructions (this file)
204
205## Local vs Cloud Storage
206
207When running locally with `apify run`, the Apify SDK emulates Cloud storage APIs using the local `storage/` directory. This local storage behaves differently from Cloud storage:
208
209- **Local storage is NOT persistent** - The `storage/` directory is meant for local development and testing only. Data stored there (datasets, key-value stores, request queues) exists only on your local disk.
210- **Local storage is NOT automatically pushed to Apify Console** - Running `apify run` does not upload any storage data to the Apify platform. The data stays local.
211- **Each local run may overwrite previous data** - The local `storage/` directory is reused between runs, but this is local-only behavior, not Cloud persistence.
212- **Cloud storage only works when running on Apify platform** - After deploying with `apify push` and running the Actor in the Cloud, storage calls (`Actor.pushData()`, `Actor.setValue()`, etc.) interact with real Apify Cloud storage, which is then visible in the Apify Console.
213- **To verify Actor output, deploy and run in Cloud** - Do not rely on local `storage/` contents as proof that data will appear in the Apify Console. Always test by deploying (`apify push`) and running the Actor on the platform.
214
215## Actor Input Schema
216
217The input schema defines the input parameters for an Actor. It's a JSON object comprising various field types supported by the Apify platform.
218
219### Structure
220
221```json
222{
223 "title": "<INPUT-SCHEMA-TITLE>",
224 "type": "object",
225 "schemaVersion": 1,
226 "properties": {/* define input fields here */},
227 "required": []
228}
229```
230
231### Example
232
233```json
234{
235 "title": "E-commerce Product Scraper Input",
236 "type": "object",
237 "schemaVersion": 1,
238 "properties": {
239 "startUrls": {
240 "title": "Start URLs",
241 "type": "array",
242 "description": "URLs to start scraping from (category pages or product pages)",
243 "editor": "requestListSources",
244 "default": [{ "url": "https://example.com/category" }],
245 "prefill": [{ "url": "https://example.com/category" }]
246 },
247 "followVariants": {
248 "title": "Follow Product Variants",
249 "type": "boolean",
250 "description": "Whether to scrape product variants (different colors, sizes)",
251 "default": true
252 },
253 "maxRequestsPerCrawl": {
254 "title": "Max Requests per Crawl",
255 "type": "integer",
256 "description": "Maximum number of pages to scrape (0 = unlimited)",
257 "default": 1000,
258 "minimum": 0
259 },
260 "proxyConfiguration": {
261 "title": "Proxy Configuration",
262 "type": "object",
263 "description": "Proxy settings for anti-bot protection",
264 "editor": "proxy",
265 "default": { "useApifyProxy": false }
266 },
267 "locale": {
268 "title": "Locale",
269 "type": "string",
270 "description": "Language/country code for localized content",
271 "default": "cs",
272 "enum": ["cs", "en", "de", "sk"],
273 "enumTitles": ["Czech", "English", "German", "Slovak"]
274 }
275 },
276 "required": ["startUrls"]
277}
278```
279
280## Actor Output Schema
281
282The Actor output schema builds upon the schemas for the dataset and key-value store. It specifies where an Actor stores its output and defines templates for accessing that output. Apify Console uses these output definitions to display run results.
283
284### Structure
285
286```json
287{
288 "actorOutputSchemaVersion": 1,
289 "title": "<OUTPUT-SCHEMA-TITLE>",
290 "properties": {/* define your outputs here */}
291}
292```
293
294### Example
295
296```json
297{
298 "actorOutputSchemaVersion": 1,
299 "title": "Output schema of the files scraper",
300 "properties": {
301 "files": {
302 "type": "string",
303 "title": "Files",
304 "template": "{{links.apiDefaultKeyValueStoreUrl}}/keys"
305 },
306 "dataset": {
307 "type": "string",
308 "title": "Dataset",
309 "template": "{{links.apiDefaultDatasetUrl}}/items"
310 }
311 }
312}
313```
314
315### Output Schema Template Variables
316
317- `links` (object) - Contains quick links to most commonly used URLs
318- `links.publicRunUrl` (string) - Public run url in format `https://console.apify.com/view/runs/:runId`
319- `links.consoleRunUrl` (string) - Console run url in format `https://console.apify.com/actors/runs/:runId`
320- `links.apiRunUrl` (string) - API run url in format `https://api.apify.com/v2/actor-runs/:runId`
321- `links.apiDefaultDatasetUrl` (string) - API url of default dataset in format `https://api.apify.com/v2/datasets/:defaultDatasetId`
322- `links.apiDefaultKeyValueStoreUrl` (string) - API url of default key-value store in format `https://api.apify.com/v2/key-value-stores/:defaultKeyValueStoreId`
323- `links.containerRunUrl` (string) - URL of a webserver running inside the run in format `https://<containerId>.runs.apify.net/`
324- `run` (object) - Contains information about the run same as it is returned from the `GET Run` API endpoint
325- `run.defaultDatasetId` (string) - ID of the default dataset
326- `run.defaultKeyValueStoreId` (string) - ID of the default key-value store
327
328## Dataset Schema Specification
329
330The dataset schema defines how your Actor's output data is structured, transformed, and displayed in the Output tab in the Apify Console.
331
332### Example
333
334Consider an example Actor that calls `Actor.pushData()` to store data into dataset:
335
336```typescript
337import { Actor } from 'apify';
338// Initialize the JavaScript SDK
339await Actor.init();
340
341/**
342 * Actor code
343 */
344await Actor.pushData({
345 numericField: 10,
346 pictureUrl: 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png',
347 linkUrl: 'https://google.com',
348 textField: 'Google',
349 booleanField: true,
350 dateField: new Date(),
351 arrayField: ['#hello', '#world'],
352 objectField: {},
353});
354
355// Exit successfully
356await Actor.exit();
357```
358
359To set up the Actor's output tab UI, reference a dataset schema file in `.actor/actor.json`:
360
361```json
362{
363 "actorSpecification": 1,
364 "name": "book-library-scraper",
365 "title": "Book Library Scraper",
366 "version": "1.0.0",
367 "storages": {
368 "dataset": "./dataset_schema.json"
369 }
370}
371```
372
373Then create the dataset schema in `.actor/dataset_schema.json`:
374
375```json
376{
377 "actorSpecification": 1,
378 "fields": {},
379 "views": {
380 "overview": {
381 "title": "Overview",
382 "transformation": {
383 "fields": [
384 "pictureUrl",
385 "linkUrl",
386 "textField",
387 "booleanField",
388 "arrayField",
389 "objectField",
390 "dateField",
391 "numericField"
392 ]
393 },
394 "display": {
395 "component": "table",
396 "properties": {
397 "pictureUrl": {
398 "label": "Image",
399 "format": "image"
400 },
401 "linkUrl": {
402 "label": "Link",
403 "format": "link"
404 },
405 "textField": {
406 "label": "Text",
407 "format": "text"
408 },
409 "booleanField": {
410 "label": "Boolean",
411 "format": "boolean"
412 },
413 "arrayField": {
414 "label": "Array",
415 "format": "array"
416 },
417 "objectField": {
418 "label": "Object",
419 "format": "object"
420 },
421 "dateField": {
422 "label": "Date",
423 "format": "date"
424 },
425 "numericField": {
426 "label": "Number",
427 "format": "number"
428 }
429 }
430 }
431 }
432 }
433}
434```
435
436### Structure
437
438```json
439{
440 "actorSpecification": 1,
441 "fields": {},
442 "views": {
443 "<VIEW_NAME>": {
444 "title": "string (required)",
445 "description": "string (optional)",
446 "transformation": {
447 "fields": ["string (required)"],
448 "unwind": ["string (optional)"],
449 "flatten": ["string (optional)"],
450 "omit": ["string (optional)"],
451 "limit": "integer (optional)",
452 "desc": "boolean (optional)"
453 },
454 "display": {
455 "component": "table (required)",
456 "properties": {
457 "<FIELD_NAME>": {
458 "label": "string (optional)",
459 "format": "text|number|date|link|boolean|image|array|object (optional)"
460 }
461 }
462 }
463 }
464 }
465}
466```
467
468**Dataset Schema Properties:**
469
470- `actorSpecification` (integer, required) - Specifies the version of dataset schema structure document (currently only version 1)
471- `fields` (JSONSchema object, required) - Schema of one dataset object (use JsonSchema Draft 2020-12 or compatible)
472- `views` (DatasetView object, required) - Object with API and UI views description
473
474**DatasetView Properties:**
475
476- `title` (string, required) - Visible in UI Output tab and API
477- `description` (string, optional) - Only available in API response
478- `transformation` (ViewTransformation object, required) - Data transformation applied when loading from Dataset API
479- `display` (ViewDisplay object, required) - Output tab UI visualization definition
480
481**ViewTransformation Properties:**
482
483- `fields` (string[], required) - Fields to present in output (order matches column order)
484- `unwind` (string[], optional) - Deconstructs nested children into parent object
485- `flatten` (string[], optional) - Transforms nested object into flat structure
486- `omit` (string[], optional) - Removes specified fields from output
487- `limit` (integer, optional) - Maximum number of results (default: all)
488- `desc` (boolean, optional) - Sort order (true = newest first)
489
490**ViewDisplay Properties:**
491
492- `component` (string, required) - Only `table` is available
493- `properties` (Object, optional) - Keys matching `transformation.fields` with ViewDisplayProperty values
494
495**ViewDisplayProperty Properties:**
496
497- `label` (string, optional) - Table column header
498- `format` (string, optional) - One of: `text`, `number`, `date`, `link`, `boolean`, `image`, `array`, `object`
499
500## Key-Value Store Schema Specification
501
502The key-value store schema organizes keys into logical groups called collections for easier data management.
503
504### Example
505
506Consider an example Actor that calls `Actor.setValue()` to save records into the key-value store:
507
508```typescript
509import { Actor } from 'apify';
510// Initialize the JavaScript SDK
511await Actor.init();
512
513/**
514 * Actor code
515 */
516await Actor.setValue('document-1', 'my text data', { contentType: 'text/plain' });
517
518await Actor.setValue(`image-${imageID}`, imageBuffer, { contentType: 'image/jpeg' });
519
520// Exit successfully
521await Actor.exit();
522```
523
524To configure the key-value store schema, reference a schema file in `.actor/actor.json`:
525
526```json
527{
528 "actorSpecification": 1,
529 "name": "data-collector",
530 "title": "Data Collector",
531 "version": "1.0.0",
532 "storages": {
533 "keyValueStore": "./key_value_store_schema.json"
534 }
535}
536```
537
538Then create the key-value store schema in `.actor/key_value_store_schema.json`:
539
540```json
541{
542 "actorKeyValueStoreSchemaVersion": 1,
543 "title": "Key-Value Store Schema",
544 "collections": {
545 "documents": {
546 "title": "Documents",
547 "description": "Text documents stored by the Actor",
548 "keyPrefix": "document-"
549 },
550 "images": {
551 "title": "Images",
552 "description": "Images stored by the Actor",
553 "keyPrefix": "image-",
554 "contentTypes": ["image/jpeg"]
555 }
556 }
557}
558```
559
560### Structure
561
562```json
563{
564 "actorKeyValueStoreSchemaVersion": 1,
565 "title": "string (required)",
566 "description": "string (optional)",
567 "collections": {
568 "<COLLECTION_NAME>": {
569 "title": "string (required)",
570 "description": "string (optional)",
571 "key": "string (conditional - use key OR keyPrefix)",
572 "keyPrefix": "string (conditional - use key OR keyPrefix)",
573 "contentTypes": ["string (optional)"],
574 "jsonSchema": "object (optional)"
575 }
576 }
577}
578```
579
580**Key-Value Store Schema Properties:**
581
582- `actorKeyValueStoreSchemaVersion` (integer, required) - Version of key-value store schema structure document (currently only version 1)
583- `title` (string, required) - Title of the schema
584- `description` (string, optional) - Description of the schema
585- `collections` (Object, required) - Object where each key is a collection ID and value is a Collection object
586
587**Collection Properties:**
588
589- `title` (string, required) - Collection title shown in UI tabs
590- `description` (string, optional) - Description appearing in UI tooltips
591- `key` (string, conditional) - Single specific key for this collection
592- `keyPrefix` (string, conditional) - Prefix for keys included in this collection
593- `contentTypes` (string[], optional) - Allowed content types for validation
594- `jsonSchema` (object, optional) - JSON Schema Draft 07 format for `application/json` content type validation
595
596Either `key` or `keyPrefix` must be specified for each collection, but not both.
597
598## Actor README
599
600**Always generate a README.md file as part of Actor development.** The README is the Actor's public landing page on Apify Store - it serves as SEO, first impression, documentation, and support page combined.
601
602### Required: Generate README automatically
603
604When building an Actor, always create a `README.md` in the project root. Do not wait for the user to ask for it. The README is a critical part of a complete Actor.
605
606### README structure
607
608Write in Markdown. Use H2 (`##`) for main sections (these become the table of contents) and H3 (`###`) for subsections. Do not use H1 - the Actor name is automatically the H1. Aim for at least 300 words.
609
610Include these sections in order:
611
6121. **What does [Actor name] do?** - 2-3 sentences explaining what it does, what data it extracts, and how to try it. Link to the target website. Mention Apify platform advantages (API access, scheduling, integrations, proxy rotation, monitoring).
6132. **Why use [Actor name]?** - Business use cases and benefits.
6143. **How to use [Actor name]** - Numbered step-by-step tutorial. Keep it simple and reassuring.
6154. **Input** - Describe input fields. Reference the Input tab. Optionally include a screenshot or JSON example of the input schema.
6165. **Output** - Show a simplified JSON output example. Mention "You can download the dataset in various formats such as JSON, HTML, CSV, or Excel."
6176. **Data table** - If the Actor extracts data, include a table of the main data fields it outputs.
6187. **Pricing / Cost estimation** - Set expectations on cost. Mention free tier limits if applicable. Frame as "How much does it cost to scrape [target site]?"
6198. **Tips or Advanced options** - How to optimize runs, limit compute units, improve speed or accuracy.
6209. **FAQ, disclaimers, and support** - Legality disclaimer for scrapers, known limitations, link to Issues tab for feedback, mention custom solution availability.
621
622### README best practices
623
624- Write SEO-friendly headings with relevant keywords (e.g., "How to scrape [site] data" not just "Tutorial")
625- Bold the most important words in the intro
626- The first 25% of the README matters most - front-load the value proposition
627- Match the tone to the target audience: simple language for no-code users, technical details for developers
628- Include a JSON output example showing 1-2 representative items
629- Reference these top Actors for README best practices: https://apify.com/apify/instagram-scraper and https://apify.com/compass/crawler-google-places
630- Embed YouTube video URLs on their own line (Apify Console auto-renders them)
631- Use HTML for image sizing if needed; CSS is not supported
632
633## MCP Tools
634
635### Apify MCP
636
637If the Apify MCP server is configured, use these tools for documentation:
638
639- `search-apify-docs` - Search documentation
640- `fetch-apify-docs` - Get full doc pages
641
642Otherwise, reference: `@https://mcp.apify.com/`
643
644### Playwright MCP (debugging)
645
646The Playwright MCP server is a useful tool for debugging Actors that interact with the web - it lets the agent drive a real browser to inspect pages, capture selectors, and reproduce issues.
647
648Install with the Claude Code CLI:
649
650```bash
651claude mcp add playwright npx @playwright/mcp@latest
652```
653
654Or add it manually to your MCP config:
655
656```json
657{
658 "mcpServers": {
659 "playwright": {
660 "command": "npx",
661 "args": ["@playwright/mcp@latest"]
662 }
663 }
664}
665```
666
667## Resources
668
669- [docs.apify.com/llms.txt](https://docs.apify.com/llms.txt) - Quick reference
670- [docs.apify.com/llms-full.txt](https://docs.apify.com/llms-full.txt) - Complete docs
671- [crawlee.dev](https://crawlee.dev) - Crawlee documentation
672- [whitepaper.actor](https://raw.githubusercontent.com/apify/actor-whitepaper/refs/heads/master/README.md) - Complete Actor specification