
Apify Actorization
- 6 installs
- 2.3k repo stars
- Updated August 4, 2026
- apify/apify-agent-skills
This is a copy of apify-actorization by apify - installs and ranking accrue to the original listing.
apify-actorization is a Claude skill that converts an existing JavaScript, TypeScript, Python, or CLI project into an Apify Actor.
About
This skill converts an existing project into an Apify Actor, a serverless program packaged as a Docker image. It wraps JavaScript or TypeScript code with Actor.init and Actor.exit, Python code with the async context manager, or any other language via a CLI wrapper, then configures input and output schemas and deploys with apify push. A developer uses it when migrating code to Apify, wrapping a CLI tool as an Actor, or adding the Actor SDK to an existing project.
- Converts existing JavaScript/TypeScript, Python, or any-language projects into Apify Actors
- Wraps code with the Actor SDK lifecycle (Actor.init/exit, async with Actor) or a CLI wrapper
- Follows a 9-step actorization checklist ending in apify push deploy
Apify Actorization by the numbers
- 6 all-time installs (skills.sh)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
apify-actorization capabilities & compatibility
Needs an Apify account and APIFY_TOKEN; CLI installed via npm.
- Capabilities
- actor development · sdk integration · project migration · cli wrapping
- Works with
- docker
- Use cases
- api development · web scraping · devops
- Pricing
- Bring your own API key
What apify-actorization says it does
Actorization converts existing software into reusable serverless applications compatible with the Apify platform.
| JS/TS | `npm install apify` | `await Actor.init()` ... `await Actor.exit()` |
npx skills add https://github.com/apify/apify-agent-skills --skill apify-actorizationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 6 |
|---|---|
| repo stars | ★ 2.3k |
| Last updated | August 4, 2026 |
| Repository | apify/apify-agent-skills ↗ |
What it does
Convert an existing project into an Apify Actor by adding the SDK lifecycle and schemas.
Who is it for?
Migrating an existing script, CLI tool, or Crawlee project to run as an Apify Actor.
Skip if: Building a brand-new Actor from scratch (use apify-actor-development) or calling Actors from an app.
When should I use this skill?
When migrating code to Apify, wrapping a CLI tool as an Actor, or adding the Actor SDK to an existing project.
What you get
The existing project is wrapped with the Actor SDK, given input/output schemas, tested with apify run, and deployed with apify push.
- An actorized project with SDK lifecycle
- input/output schemas
- A deployed Actor
By the numbers
- 9-step actorization checklist
- 3 language paths (JS/TS, Python, CLI-based)
Files
Apify Actorization
Actorization converts existing software into reusable serverless applications compatible with the Apify platform. Actors are programs packaged as Docker images that accept well-defined JSON input, perform an action, and optionally produce structured JSON output.
Quick start
1. Run apify init in project root 2. Wrap code with SDK lifecycle (see language-specific section below) 3. Configure .actor/input_schema.json 4. Test with apify run --input '{"key": "value"}' 5. Deploy with apify push
When to use this skill
- Converting an existing project to run on the Apify platform
- Adding Apify SDK integration to a project
- Wrapping a CLI tool or script as an Actor
- Migrating a Crawlee project to Apify
Prerequisites
Verify apify CLI is installed:
apify --helpIf not installed, use one of these methods (listed in order of preference):
# Preferred: install via a package manager (provides integrity checks)
npm install -g apify-cli
# Or (Mac): brew install apify-cliSecurity note: Do NOT install the CLI by piping remote scripts to a shell
(e.g.curl ... | bashorirm ... | iex). Always use a package manager.
Verify CLI is logged in:
apify info # Should return your usernameIf not logged in, authenticate using OAuth (opens browser):
apify loginIf browser login isn't available (headless environment or CI), ensure the APIFY_TOKEN environment variable is exported (note: the variable is APIFY_TOKEN, not APIFY_API_TOKEN). The CLI reads it automatically - no explicit login needed. If the user doesn't have a token, generate one at https://console.apify.com/settings/integrations.
Apify platform environment: When the Actor runs on the Apify platform,APIFY_TOKENis auto-injected as an environment variable and the Apify SDK reads it automatically — you do not need to pass it explicitly. Locally,apify loginstores credentials in~/.apifyand the SDK uses them.
Security note: Avoid passing tokens as command-line arguments (e.g. apify login -t <token>).Arguments are visible in process listings and may be recorded in shell history.
Prefer OAuth login or environment variables instead.
Never log, print, or embed APIFY_TOKEN in source code or configuration files.Use a token with the minimum required permissions (scoped token) and rotate it periodically.
Actorization checklist
Copy this checklist to track progress:
- [ ] Step 1: Analyze project (language, entry point, inputs, outputs)
- [ ] Step 2: Run
apify initto create Actor structure - [ ] Step 3: Apply language-specific SDK integration
- [ ] Step 4: Configure
.actor/input_schema.json - [ ] Step 5: Configure
.actor/output_schema.json(if applicable) - [ ] Step 6: Update
.actor/actor.jsonmetadata - [ ] Step 7: Write README.md for Apify Store listing
- [ ] Step 8: Test locally with
apify run - [ ] Step 9: Deploy with
apify push
Step 1: Analyze the project
Before making changes, understand the project:
1. Identify the language - JavaScript/TypeScript, Python, or other 2. Find the entry point - The main file that starts execution 3. Identify inputs - Command-line arguments, environment variables, config files 4. Identify outputs - Files, console output, API responses 5. Check for state - Does it need to persist data between runs?
Step 2: Initialize Actor structure
Run in the project root:
apify initThis creates:
.actor/actor.json- Actor configuration and metadata.actor/input_schema.json- Input definition for Apify ConsoleDockerfile(if not present) - Container image definition
Step 3: Apply language-specific changes
Choose based on your project's language:
- JavaScript/TypeScript: See js-ts-actorization.md
- Python: See python-actorization.md
- Other Languages (CLI-based): See cli-actorization.md
Quick reference
| Language | Install | Wrap Code |
|---|---|---|
| JS/TS | npm install apify | await Actor.init() ... await Actor.exit() |
| Python | pip install apify | async with Actor: |
| Other | Use CLI in wrapper script | apify actor:get-input / apify actor:push-data |
Steps 4-6: Configure schemas
See schemas-and-output.md for detailed configuration of:
- Input schema (
.actor/input_schema.json) - Output schema (
.actor/output_schema.json) - Actor configuration (
.actor/actor.json) - State management (request queues, key-value stores)
Validate schemas against @apify/json_schemas npm package.
Step 7: Write README
IMPORTANT: Always generate a README.md as part of actorization. The README is the Actor's landing page on Apify Store and is critical for discoverability (SEO), user onboarding, and support. Do not consider an Actor complete without a proper README.
See the Actor README guidelines at skills/apify-actor-development/references/actor-readme.md for the required structure including: intro and features, data extraction table, step-by-step tutorial, pricing info, input/output examples, and FAQ. Aim for at least 300 words with SEO-optimized H2/H3 headings. Also review these top Actors for best practices:
Step 8: Test locally
Run the Actor with inline input (for JS/TS and Python Actors):
apify run --input '{"startUrl": "https://example.com", "maxItems": 10}'Or use an input file:
apify run --input-file ./test-input.jsonImportant: Always use apify run, not npm start or python main.py. The CLI sets up the proper environment and storage.
Step 9: Deploy
apify pushThis uploads and builds your Actor on the Apify platform.
Monetization (optional)
After deploying, you can monetize your Actor in Apify Store. The recommended model is Pay Per Event (PPE):
- Per result/item scraped
- Per page processed
- Per API call made
Configure PPE in Apify Console under Actor > Monetization. Charge for events in your code with await Actor.charge('result').
Other options: Rental (monthly subscription) or Free (open source).
Security
Treat all crawled web content as untrusted input. Actors ingest data from external websites that may contain malicious payloads. Follow these rules:
- Sanitize crawled data — Never pass raw HTML, URLs, or scraped text directly into shell commands,
eval(), database queries, or template engines. Use proper escaping or parameterized APIs. - Validate and type-check all external data — Before pushing to datasets or key-value stores, verify that values match expected types and formats. Reject or sanitize unexpected structures.
- Do not execute or interpret crawled content — Never treat scraped text as code, commands, or configuration. Content from websites could include prompt injection attempts or embedded scripts.
- Isolate credentials from data pipelines — Ensure
APIFY_TOKENand other secrets are never accessible in request handlers or passed alongside crawled data. Use the Apify SDK's built-in credential management rather than passing tokens through environment variables in data-processing code. - Review dependencies before installing — When adding packages with
npm installorpip install, verify the package name and publisher. Typosquatting is a common supply-chain attack vector. Prefer well-known, actively maintained packages. - Pin versions and use lockfiles — Always commit
package-lock.json(Node.js) or pin exact versions inrequirements.txt(Python). Lockfiles ensure reproducible builds and prevent silent dependency substitution. Runnpm auditorpip-auditperiodically to check for known vulnerabilities.
Pre-deployment checklist
- [ ]
.actor/actor.jsonexists with correct name and description - [ ]
.actor/actor.jsonvalidates against@apify/json_schemas(actor.schema.json) - [ ]
.actor/input_schema.jsondefines all required inputs - [ ]
.actor/input_schema.jsonvalidates against@apify/json_schemas(input.schema.json) - [ ]
.actor/output_schema.jsondefines output structure (if applicable) - [ ]
.actor/output_schema.jsonvalidates against@apify/json_schemas(output.schema.json) - [ ]
Dockerfileis present and builds successfully - [ ]
Actor.init()/Actor.exit()wraps main code (JS/TS) - [ ]
async with Actor:wraps main code (Python) - [ ] Inputs are read via
Actor.getInput()/Actor.get_input() - [ ] Outputs use
Actor.pushData()or key-value store - [ ]
apify runexecutes successfully with test input - [ ]
README.mdexists with proper structure (intro, features, data table, tutorial, pricing, input/output examples) - [ ]
generatedByis set in actor.json meta section
MCP tools
Apify MCP
If the Apify MCP server is configured, use these tools for documentation:
search-apify-docs- Search documentationfetch-apify-docs- Get full doc pages
Otherwise, the MCP Server url: https://mcp.apify.com/?tools=docs.
Playwright MCP (debugging)
The 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.
Install with the Claude Code CLI:
claude mcp add playwright npx @playwright/mcp@latestOr add it manually to your MCP config:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
}Resources
- Actorization Academy - Comprehensive guide
- Apify SDK for JavaScript - Full SDK reference
- Apify SDK for Python - Full SDK reference
- Apify CLI Reference - CLI commands
- Actor Specification - Complete specification
CLI-based Actorization
For languages without an SDK (Go, Rust, Java, etc.), create a wrapper script that uses the Apify CLI.
Create wrapper script
Create start.sh in project root:
#!/bin/bash
set -e
# Get input from Apify key-value store
INPUT=$(apify actor:get-input)
# Parse input values (adjust based on your input schema)
MY_PARAM=$(echo "$INPUT" | jq -r '.myParam // "default"')
# Run your application with the input
./your-application --param "$MY_PARAM"
# If your app writes to a file, push it to key-value store
# apify actor:set-value OUTPUT --contentType application/json < output.json
# Or push structured data to dataset
# apify actor:push-data '{"result": "value"}'Update Dockerfile
Reference the cli-start template Dockerfile which includes the ubi utility for installing binaries from GitHub releases.
FROM apify/actor-node:20
# Install ubi for easy GitHub release installation
RUN curl --silent --location \
https://raw.githubusercontent.com/houseabsolute/ubi/master/bootstrap/bootstrap-ubi.sh | sh
# Install your CLI tool from GitHub releases (example)
# RUN ubi --project your-org/your-tool --in /usr/local/bin
# Or install apify-cli and jq manually
RUN npm install -g apify-cli
RUN apt-get update && apt-get install -y jq
# Copy your application
COPY . .
# Build your application if needed
# RUN ./build.sh
# Make start script executable
RUN chmod +x start.sh
# Run the wrapper script
CMD ["./start.sh"]Testing CLI-based Actors
For CLI-based Actors (shell wrapper scripts), you may need to test the underlying application directly with mock input, as apify run requires a Node.js or Python entry point.
Test your wrapper script locally:
# Set up mock input
export INPUT='{"myParam": "test-value"}'
# Run wrapper script
./start.shCLI commands reference
| Command | Description |
|---|---|
apify actor:get-input | Get input JSON from key-value store |
apify actor:set-value KEY | Store value in key-value store |
apify actor:push-data JSON | Push data to dataset |
apify actor:get-value KEY | Retrieve value from key-value store |
JavaScript/TypeScript Actorization
Install the Apify SDK
npm install apifyWrap main code with Actor lifecycle
import { Actor } from 'apify';
// Initialize connection to Apify platform
await Actor.init();
// ============================================
// Your existing code goes here
// ============================================
// Example: Get input from Apify Console or API
const input = await Actor.getInput();
console.log('Input:', input);
// Example: Your crawler or processing logic
// const crawler = new PlaywrightCrawler({ ... });
// await crawler.run([input.startUrl]);
// Example: Push results to dataset
// await Actor.pushData({ result: 'data' });
// ============================================
// End of your code
// ============================================
// Graceful shutdown
await Actor.exit();Key points
Actor.init()configures storage to use Apify API when running on platformActor.exit()handles graceful shutdown and cleanup- Both calls must be awaited
- Local execution remains unchanged - the SDK automatically detects the environment
Crawlee projects
Crawlee projects require minimal changes - just wrap with Actor lifecycle:
import { Actor } from 'apify';
import { PlaywrightCrawler } from 'crawlee';
await Actor.init();
// Get and validate input
const input = await Actor.getInput();
const {
startUrl = 'https://example.com',
maxItems = 100,
} = input ?? {};
let itemCount = 0;
const crawler = new PlaywrightCrawler({
requestHandler: async ({ page, request, pushData }) => {
if (itemCount >= maxItems) return;
const title = await page.title();
await pushData({ url: request.url, title });
itemCount++;
},
});
await crawler.run([startUrl]);
await Actor.exit();Express/HTTP servers
For web servers, use standby mode in actor.json:
{
"actorSpecification": 1,
"name": "my-api",
"usesStandbyMode": true
}Then implement readiness probe. See standby-mode.md.
Batch processing scripts
import { Actor } from 'apify';
await Actor.init();
const input = await Actor.getInput();
const items = input.items || [];
for (const item of items) {
const result = processItem(item);
await Actor.pushData(result);
}
await Actor.exit();Python Actorization
Install the Apify SDK
pip install apifyWrap main function with Actor context manager
import asyncio
from apify import Actor
async def main() -> None:
async with Actor:
# ============================================
# Your existing code goes here
# ============================================
# Example: Get input from Apify Console or API
actor_input = await Actor.get_input()
print(f'Input: {actor_input}')
# Example: Your crawler or processing logic
# crawler = PlaywrightCrawler(...)
# await crawler.run([actor_input.get('startUrl')])
# Example: Push results to dataset
# await Actor.push_data({'result': 'data'})
# ============================================
# End of your code
# ============================================
if __name__ == '__main__':
asyncio.run(main())Key points
async with Actor:handles both initialization and cleanup- Automatically manages platform event listeners and graceful shutdown
- Local execution remains unchanged - the SDK automatically detects the environment
Crawlee Python projects
import asyncio
from apify import Actor
from crawlee.playwright_crawler import PlaywrightCrawler
async def main() -> None:
async with Actor:
# Get and validate input
actor_input = await Actor.get_input() or {}
start_url = actor_input.get('startUrl', 'https://example.com')
max_items = actor_input.get('maxItems', 100)
item_count = 0
async def request_handler(context):
nonlocal item_count
if item_count >= max_items:
return
title = await context.page.title()
await context.push_data({'url': context.request.url, 'title': title})
item_count += 1
crawler = PlaywrightCrawler(request_handler=request_handler)
await crawler.run([start_url])
if __name__ == '__main__':
asyncio.run(main())Batch processing scripts
import asyncio
from apify import Actor
async def main() -> None:
async with Actor:
actor_input = await Actor.get_input() or {}
items = actor_input.get('items', [])
for item in items:
result = process_item(item)
await Actor.push_data(result)
if __name__ == '__main__':
asyncio.run(main())Schemas and output configuration
Input schema
Map your application's inputs to .actor/input_schema.json. Validate against the JSON Schema from the @apify/json_schemas npm package (input.schema.json).
{
"title": "My Actor Input",
"type": "object",
"schemaVersion": 1,
"properties": {
"startUrl": {
"title": "Start URL",
"type": "string",
"description": "The URL to start processing from",
"editor": "textfield",
"prefill": "https://example.com"
},
"maxItems": {
"title": "Max Items",
"type": "integer",
"description": "Maximum number of items to process",
"default": 100,
"minimum": 1
}
},
"required": ["startUrl"]
}Mapping guidelines
- Command-line arguments → input schema properties
- Environment variables → input schema or Actor env vars in actor.json
- Config files → input schema with object/array types
- Flatten deeply nested structures for better UX
Output schema
Define output structure in .actor/output_schema.json. Validate against the JSON Schema from the @apify/json_schemas npm package (output.schema.json).
For table-like data (multiple items)
- Use
Actor.pushData()(JS) orActor.push_data()(Python) - Each item becomes a row in the dataset
For single files or blobs
- Use key-value store:
Actor.setValue()/Actor.set_value() - Get the public URL and include it in the dataset:
// Store file with public access
await Actor.setValue('report.pdf', pdfBuffer, { contentType: 'application/pdf' });
// Get the public URL
const storeInfo = await Actor.openKeyValueStore();
const publicUrl = `https://api.apify.com/v2/key-value-stores/${storeInfo.id}/records/report.pdf`;
// Include URL in dataset output
await Actor.pushData({ reportUrl: publicUrl });For multiple files with a common prefix (collections)
// Store multiple files with a prefix
for (const [name, data] of files) {
await Actor.setValue(`screenshots/${name}`, data, { contentType: 'image/png' });
}
// Files are accessible at: .../records/screenshots%2F{name}Actor configuration (actor.json)
Configure .actor/actor.json. Validate against the JSON Schema from the @apify/json_schemas npm package (actor.schema.json).
{
"actorSpecification": 1,
"name": "my-actor",
"title": "My Actor",
"description": "Brief description of what the Actor does",
"version": "1.0.0",
"meta": {
"templateId": "ts_empty",
"generatedBy": "Claude Code with Claude Opus 4.5"
},
"input": "./input_schema.json",
"dockerfile": "../Dockerfile"
}Important: Fill in the generatedBy property with the tool/model used.
State management
Request queue - for pausable task processing
The request queue works for any task processing, not just web scraping. Use a dummy URL with custom uniqueKey and userData for non-URL tasks:
const requestQueue = await Actor.openRequestQueue();
// Add tasks to the queue (works for any processing, not just URLs)
await requestQueue.addRequest({
url: 'https://placeholder.local', // Dummy URL for non-scraping tasks
uniqueKey: `task-${taskId}`, // Unique identifier for deduplication
userData: { itemId: 123, action: 'process' }, // Your custom task data
});
// Process tasks from the queue (with Crawlee)
const crawler = new BasicCrawler({
requestQueue,
requestHandler: async ({ request }) => {
const { itemId, action } = request.userData;
// Process your task using userData
await processTask(itemId, action);
},
});
await crawler.run();
// Or manually consume without Crawlee:
let request;
while ((request = await requestQueue.fetchNextRequest())) {
await processTask(request.userData);
await requestQueue.markRequestHandled(request);
}Key-value store - for checkpoint state
// Save state
await Actor.setValue('STATE', { processedCount: 100 });
// Restore state on restart
const state = await Actor.getValue('STATE') || { processedCount: 0 };Related skills
FAQ
How is code wrapped per language?
JS/TS uses await Actor.init() ... await Actor.exit(), Python uses async with Actor:, and other languages use a CLI wrapper with apify actor:get-input and apify actor:push-data.
What starts the process?
Run apify init in the project root to create .actor/actor.json, .actor/input_schema.json, and a Dockerfile if missing.