Apify Actor Developer
Build, test, deploy, and monetize Apify Actors - serverless cloud applications for web scraping, data extraction, and automation.
Prerequisites
Ensure these are available:
- Node.js 18+ or Python 3.9+
- Apify CLI:
npm install -g apify-cli
- Logged in:
apify login
Workflow
Phase 1: Project Initialization
Create Actor from template:
# JavaScript templates
apify create my-actor -t js-start # Basic starter
apify create my-actor -t js-crawlee-cheerio # Fast HTTP scraping
apify create my-actor -t js-crawlee-playwright-chrome # Browser automation
apify create my-actor -t js-crawlee-puppeteer-chrome # Puppeteer-based
apify create my-actor -t js-langchain # LangChain AI
apify create my-actor -t js-langgraph-agent # LangGraph agent
# TypeScript templates
apify create my-actor -t ts-start # Basic starter
apify create my-actor -t ts-crawlee-cheerio # Fast HTTP scraping
apify create my-actor -t ts-crawlee-playwright-chrome # Browser automation
apify create my-actor -t ts-crawlee-puppeteer-chrome # Puppeteer-based
apify create my-actor -t ts-mcp-proxy # MCP server proxy
# Python templates
apify create my-actor -t python-start # Basic starter
apify create my-actor -t python-crawlee-beautifulsoup # BeautifulSoup crawler
apify create my-actor -t python-crawlee-playwright # Playwright crawler
apify create my-actor -t python-playwright # Playwright scraper
apify create my-actor -t python-selenium # Selenium scraper
apify create my-actor -t python-scrapy # Scrapy integration
apify create my-actor -t python-crewai # CrewAI agents
apify create my-actor -t python-langgraph # LangGraph agents
apify create my-actor -t python-pydanticai # PydanticAI
apify create my-actor -t python-mcp-proxy # MCP server proxy
Project structure created:
my-actor/
├── .actor/
│ ├── actor.json # Actor metadata and configuration
│ ├── input_schema.json # Input UI and validation
│ ├── dataset_schema.json # Output structure (optional)
│ └── pay_per_event.json # PPE monetization config (optional)
├── src/
│ └── main.js # Main entry point (or main.py)
├── README.md # Documentation (becomes Store page)
├── Dockerfile # Build configuration
└── package.json # Dependencies (or requirements.txt)
Phase 2: Define Actor Configuration
Configure .actor/actor.json:
{
"actorSpecification": 1,
"name": "my-scraper",
"title": "My Web Scraper",
"description": "Scrapes data from websites efficiently",
"version": "1.0",
"buildTag": "latest",
"input": "./input_schema.json",
"storages": {
"dataset": "./dataset_schema.json"
}
}
Design input schema (.actor/input_schema.json):
{
"title": "My Scraper Input",
"type": "object",
"schemaVersion": 1,
"description": "Configure the scraper settings. <a href='https://example.com/guide' target='_blank'>See full guide</a>",
"properties": {
"startUrls": {
"title": "Start URLs",
"type": "array",
"description": "URLs to start scraping from",
"editor": "requestListSources",
"prefill": [{ "url": "https://example.com" }]
},
"maxItems": {
"title": "Max Items",
"type": "integer",
"description": "Maximum number of items to scrape (0 = unlimited)",
"default": 100,
"minimum": 0,
"editor": "number"
},
"proxyConfig": {
"title": "Proxy Configuration",
"type": "object",
"description": "Select proxies for anti-blocking",
"editor": "proxy",
"prefill": { "useApifyProxy": true },
"sectionCaption": "Advanced Settings",
"sectionDescription": "Configure proxy and performance options"
}
},
"required": ["startUrls"]
}
Input schema editor types:
textfield - Single line text
textarea - Multi-line text
javascript / python - Code with syntax highlighting
number - Numeric input with min/max validation
select - Dropdown (requires enum or enumSuggestedValues)
requestListSources - URL list for Crawlee
proxy - Apify proxy configuration
datepicker - Date selection (absolute/relative)
checkbox - Boolean toggle
json - Raw JSON editor
keyValue - Key-value pairs
stringList - Array of strings
hidden - Hidden field
Phase 3: Implement Actor Logic
JavaScript/TypeScript Actor (src/main.js):
import { Actor } from 'apify';
import { CheerioCrawler } from 'crawlee';
await Actor.init();
// Get input
const { startUrls, maxItems = 100, proxyConfig } = await Actor.getInput();
// Configure proxy
const proxyConfiguration = await Actor.createProxyConfiguration(proxyConfig);
let itemCount = 0;
const crawler = new CheerioCrawler({
proxyConfiguration,
maxRequestsPerCrawl: maxItems || undefined,
async requestHandler({ $, request, enqueueLinks }) {
// Extract data
const title = $('h1').text().trim();
const description = $('meta[name="description"]').attr('content');
// Save to dataset
await Actor.pushData({
url: request.url,
title,
description,
scrapedAt: new Date().toISOString(),
});
itemCount++;
if (maxItems && itemCount >= maxItems) return;
// Follow links
await enqueueLinks({
globs: ['https://example.com/**'],
});
},
});
await crawler.run(startUrls);
await Actor.exit(`Scraped ${itemCount} items`);
Python Actor (src/main.py):
import asyncio
from apify import Actor
async def main():
async with Actor:
# Get input
actor_input = await Actor.get_input() or {}
start_urls = actor_input.get('startUrls', [])
max_items = actor_input.get('maxItems', 100)
item_count = 0
# Simple example without Crawlee
for url_obj in start_urls:
url = url_obj.get('url')
# Your scraping logic here
await Actor.push_data({
'url': url,
'status': 'scraped',
})
item_count += 1
if max_items and item_count >= max_items:
break
await Actor.set_status_message(f'Scraped {item_count} items')
if __name__ == '__main__':
asyncio.run(main())
Python with Crawlee (src/main.py):
import asyncio
from apify import Actor
from crawlee.playwright_crawler import PlaywrightCrawler, PlaywrightCrawlingContext
async def main():
async with Actor:
actor_input = await Actor.get_input() or {}
start_urls = [url['url'] for url in actor_input.get('startUrls', [])]
crawler = PlaywrightCrawler(
max_requests_per_crawl=actor_input.get('maxItems', 100),
)
@crawler.router.default_handler
async def request_handler(context: PlaywrightCrawlingContext):
page = context.page
title = await page.title()
await Actor.push_data({
'url': context.request.url,
'title': title,
})
await context.enqueue_links()
await crawler.run(start_urls)
if __name__ == '__main__':
asyncio.run(main())
Phase 4: Local Testing
Test locally:
# Run with default input
apify run
# Run with purged storage (fresh start)
apify run --purge
# View results
cat storage/datasets/default/*.json
Validate input schema:
apify validate-schema .actor/input_schema.json
Phase 5: Deploy to Apify Platform
Push to Apify:
apify push
This uploads code, builds Docker image, and creates/updates the Actor.
Alternative: GitHub integration:
- Connect GitHub repo in Apify Console
- Auto-builds on push to main branch
- Better for collaboration and version control
Phase 6: Write README Documentation
Create compelling README.md:
# My Web Scraper
Scrape data from websites efficiently with anti-blocking and proxy support.
## Features
- Fast parallel scraping with Crawlee
- Automatic proxy rotation
- Structured JSON/CSV output
- Handles JavaScript-rendered pages
## Input
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| startUrls | array | Yes | URLs to start scraping |
| maxItems | integer | No | Max items (default: 100) |
## Output
```json
{
"url": "https://example.com/page",
"title": "Page Title",
"description": "Meta description",
"scrapedAt": "2024-01-15T10:30:00Z"
}
Usage
Via Apify Console
- Click "Start" on the Actor page
- Enter your start URLs
- Click "Run"
Via API
curl -X POST "https://api.apify.com/v2/acts/YOUR_ACTOR/runs" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"startUrls": [{"url": "https://example.com"}]}'
Integrations
- Zapier, Make, n8n support
- Webhooks for notifications
- Schedule runs via cron
Cost Estimation
~$X per 1,000 results using datacenter proxies.
```
Phase 7: Monetization Setup
Choose pricing model:
Option A: Pay-Per-Event (PPE) - Most flexible, recommended
- Charge for custom events (pages scraped, API calls, etc.)
- You earn 80% revenue minus platform costs
- AI/MCP compatible, priority store placement
Option B: Pay-Per-Result (PPR)
- Charge per dataset item produced
- Simpler to implement
- You earn 80% revenue minus platform costs
Option C: Rental
- Monthly subscription fee
- Users pay their own platform costs
- You earn 80% of rental fee
Implement PPE charging (.actor/pay_per_event.json):
{
"schemaVersion": 1,
"events": [
{
"name": "apify-actor-start",
"priceUsd": 0.00005,
"description": "Actor initialization"
},
{
"name": "page-scraped",
"priceUsd": 0.002,
"description": "Per page scraped"
},
{
"name": "result-saved",
"priceUsd": 0.001,
"description": "Per result saved to dataset"
}
]
}
Charge events in code:
// JavaScript - Option 1: Charge with pushData
await Actor.pushData({ title, url }, 'result-saved');
// JavaScript - Option 2: Charge separately
await Actor.charge({ eventName: 'page-scraped', count: 1 });
# Python
await Actor.push_data({'title': title, 'url': url}, 'result-saved')
await Actor.charge(event_name='page-scraped', count=1)
Configure in Apify Console:
- Go to Actor -> Publication -> Monetization
- Set up billing details for payouts
- Choose pricing model via wizard
- Set event prices
Phase 8: Publish to Store
Publication checklist:
SEO optimization:
- Use keywords in title and description
- Add "use cases" section
- Include integration examples
- Mention specific websites/platforms supported
Apify SDK Reference
Core Methods
// Initialize/Exit
await Actor.init();
await Actor.exit('Success message');
await Actor.fail('Error message');
// Input/Output
const input = await Actor.getInput();
await Actor.pushData({ key: 'value' });
await Actor.setValue('key', 'value'); // Key-value store
const value = await Actor.getValue('key');
// Storage
const dataset = await Actor.openDataset('name');
const kvStore = await Actor.openKeyValueStore('name');
const requestQueue = await Actor.openRequestQueue('name');
// Platform features
const proxyConfig = await Actor.createProxyConfiguration(input.proxy);
await Actor.setStatusMessage('Processing...');
// PPE charging
await Actor.charge({ eventName: 'my-event', count: 1 });
Crawlee Crawler Types
| Crawler |
Use Case |
Speed |
JS Rendering |
| CheerioCrawler |
Static HTML |
Fastest |
No |
| PlaywrightCrawler |
Dynamic pages |
Medium |
Yes |
| PuppeteerCrawler |
Dynamic pages |
Medium |
Yes |
| HttpCrawler |
API calls |
Fastest |
No |
| JSDOMCrawler |
Light DOM parsing |
Fast |
Partial |
All Available Templates
JavaScript
js-start - Basic starter
js-crawlee-cheerio - Cheerio crawler
js-crawlee-playwright-chrome - Playwright browser
js-crawlee-puppeteer-chrome - Puppeteer browser
js-crawlee-playwright-camoufox - Camoufox (anti-detect)
js-langchain - LangChain integration
js-langgraph-agent - LangGraph agent
js-standby - HTTP server (Standby mode)
js-empty - Empty project
TypeScript
ts-start - Basic starter
ts-crawlee-cheerio - Cheerio crawler
ts-crawlee-playwright-chrome - Playwright browser
ts-crawlee-puppeteer-chrome - Puppeteer browser
ts-mcp-proxy - MCP server proxy
ts-mcp-empty - Empty MCP server
ts-standby - HTTP server
ts-empty - Empty project
Python
python-start - Basic starter
python-crawlee-beautifulsoup - BeautifulSoup crawler
python-crawlee-playwright - Playwright crawler
python-crawlee-parsel - Parsel crawler
python-playwright - Playwright scraper
python-selenium - Selenium scraper
python-scrapy - Scrapy integration
python-crewai - CrewAI agents
python-langgraph - LangGraph agents
python-pydanticai - PydanticAI
python-mcp-proxy - MCP server proxy
python-standby - HTTP server
python-empty - Empty project
Pricing Strategy Tips
- Research competitors - Check similar Actors in Store
- Calculate costs - Run tests, check Analytics tab
- Start competitive - Most prices: $1-10 per 1,000 results
- Use PPE for flexibility - Charge for what users actually use
- Offer free tier - Low maxItems for testing
Maintenance Commitment
Reserve ~2 hours/week for:
- Bug fixes and user support
- Keeping up with website changes
- Responding to Issues tab
- Improving documentation
Examples
Example 1: Simple Product Scraper
import { Actor } from 'apify';
import { CheerioCrawler } from 'crawlee';
await Actor.init();
const { startUrls } = await Actor.getInput();
const crawler = new CheerioCrawler({
async requestHandler({ $, request }) {
const products = [];
$('.product').each((_, el) => {
products.push({
name: $(el).find('.name').text(),
price: $(el).find('.price').text(),
url: request.url,
});
});
await Actor.pushData(products);
},
});
await crawler.run(startUrls);
await Actor.exit();
Example 2: AI Agent Actor (Python with CrewAI)
import asyncio
from apify import Actor
from crewai import Agent, Task, Crew
async def main():
async with Actor:
input_data = await Actor.get_input()
query = input_data.get('query')
researcher = Agent(
role='Researcher',
goal='Find accurate information',
backstory='Expert researcher',
)
task = Task(
description=query,
agent=researcher,
)
crew = Crew(agents=[researcher], tasks=[task])
result = crew.kickoff()
await Actor.push_data({'query': query, 'result': str(result)})
if __name__ == '__main__':
asyncio.run(main())
Resources
1---2name: apify-actor-developer3description: Build and monetize Apify Actors (web scrapers, automation tools, AI agents). Use when user wants to create an Actor, scraper, crawler, web automation, publish to Apify Store, set up pay-per-event/pay-per-result pricing, or integrate with Crawlee. Covers full lifecycle from development to monetization.4---56# Apify Actor Developer78Build, test, deploy, and monetize Apify Actors - serverless cloud applications for web scraping, data extraction, and automation.910## Prerequisites1112Ensure these are available:13- Node.js 18+ or Python 3.9+14- Apify CLI: `npm install -g apify-cli`15- Logged in: `apify login`1617## Workflow1819### Phase 1: Project Initialization20211. **Create Actor from template**:22 ```bash23 # JavaScript templates24 apify create my-actor -t js-start # Basic starter25 apify create my-actor -t js-crawlee-cheerio # Fast HTTP scraping26 apify create my-actor -t js-crawlee-playwright-chrome # Browser automation27 apify create my-actor -t js-crawlee-puppeteer-chrome # Puppeteer-based28 apify create my-actor -t js-langchain # LangChain AI29 apify create my-actor -t js-langgraph-agent # LangGraph agent3031 # TypeScript templates32 apify create my-actor -t ts-start # Basic starter33 apify create my-actor -t ts-crawlee-cheerio # Fast HTTP scraping34 apify create my-actor -t ts-crawlee-playwright-chrome # Browser automation35 apify create my-actor -t ts-crawlee-puppeteer-chrome # Puppeteer-based36 apify create my-actor -t ts-mcp-proxy # MCP server proxy3738 # Python templates39 apify create my-actor -t python-start # Basic starter40 apify create my-actor -t python-crawlee-beautifulsoup # BeautifulSoup crawler41 apify create my-actor -t python-crawlee-playwright # Playwright crawler42 apify create my-actor -t python-playwright # Playwright scraper43 apify create my-actor -t python-selenium # Selenium scraper44 apify create my-actor -t python-scrapy # Scrapy integration45 apify create my-actor -t python-crewai # CrewAI agents46 apify create my-actor -t python-langgraph # LangGraph agents47 apify create my-actor -t python-pydanticai # PydanticAI48 apify create my-actor -t python-mcp-proxy # MCP server proxy49 ```50512. **Project structure created**:52 ```53 my-actor/54 ├── .actor/55 │ ├── actor.json # Actor metadata and configuration56 │ ├── input_schema.json # Input UI and validation57 │ ├── dataset_schema.json # Output structure (optional)58 │ └── pay_per_event.json # PPE monetization config (optional)59 ├── src/60 │ └── main.js # Main entry point (or main.py)61 ├── README.md # Documentation (becomes Store page)62 ├── Dockerfile # Build configuration63 └── package.json # Dependencies (or requirements.txt)64 ```6566### Phase 2: Define Actor Configuration67683. **Configure `.actor/actor.json`**:69 ```json70 {71 "actorSpecification": 1,72 "name": "my-scraper",73 "title": "My Web Scraper",74 "description": "Scrapes data from websites efficiently",75 "version": "1.0",76 "buildTag": "latest",77 "input": "./input_schema.json",78 "storages": {79 "dataset": "./dataset_schema.json"80 }81 }82 ```83844. **Design input schema** (`.actor/input_schema.json`):85 ```json86 {87 "title": "My Scraper Input",88 "type": "object",89 "schemaVersion": 1,90 "description": "Configure the scraper settings. <a href='https://example.com/guide' target='_blank'>See full guide</a>",91 "properties": {92 "startUrls": {93 "title": "Start URLs",94 "type": "array",95 "description": "URLs to start scraping from",96 "editor": "requestListSources",97 "prefill": [{ "url": "https://example.com" }]98 },99 "maxItems": {100 "title": "Max Items",101 "type": "integer",102 "description": "Maximum number of items to scrape (0 = unlimited)",103 "default": 100,104 "minimum": 0,105 "editor": "number"106 },107 "proxyConfig": {108 "title": "Proxy Configuration",109 "type": "object",110 "description": "Select proxies for anti-blocking",111 "editor": "proxy",112 "prefill": { "useApifyProxy": true },113 "sectionCaption": "Advanced Settings",114 "sectionDescription": "Configure proxy and performance options"115 }116 },117 "required": ["startUrls"]118 }119 ```120121 **Input schema editor types**:122 - `textfield` - Single line text123 - `textarea` - Multi-line text124 - `javascript` / `python` - Code with syntax highlighting125 - `number` - Numeric input with min/max validation126 - `select` - Dropdown (requires `enum` or `enumSuggestedValues`)127 - `requestListSources` - URL list for Crawlee128 - `proxy` - Apify proxy configuration129 - `datepicker` - Date selection (absolute/relative)130 - `checkbox` - Boolean toggle131 - `json` - Raw JSON editor132 - `keyValue` - Key-value pairs133 - `stringList` - Array of strings134 - `hidden` - Hidden field135136### Phase 3: Implement Actor Logic1371385. **JavaScript/TypeScript Actor** (`src/main.js`):139 ```javascript140 import { Actor } from 'apify';141 import { CheerioCrawler } from 'crawlee';142143 await Actor.init();144145 // Get input146 const { startUrls, maxItems = 100, proxyConfig } = await Actor.getInput();147148 // Configure proxy149 const proxyConfiguration = await Actor.createProxyConfiguration(proxyConfig);150151 let itemCount = 0;152153 const crawler = new CheerioCrawler({154 proxyConfiguration,155 maxRequestsPerCrawl: maxItems || undefined,156157 async requestHandler({ $, request, enqueueLinks }) {158 // Extract data159 const title = $('h1').text().trim();160 const description = $('meta[name="description"]').attr('content');161162 // Save to dataset163 await Actor.pushData({164 url: request.url,165 title,166 description,167 scrapedAt: new Date().toISOString(),168 });169170 itemCount++;171 if (maxItems && itemCount >= maxItems) return;172173 // Follow links174 await enqueueLinks({175 globs: ['https://example.com/**'],176 });177 },178 });179180 await crawler.run(startUrls);181182 await Actor.exit(`Scraped ${itemCount} items`);183 ```1841856. **Python Actor** (`src/main.py`):186 ```python187 import asyncio188 from apify import Actor189190 async def main():191 async with Actor:192 # Get input193 actor_input = await Actor.get_input() or {}194 start_urls = actor_input.get('startUrls', [])195 max_items = actor_input.get('maxItems', 100)196197 item_count = 0198199 # Simple example without Crawlee200 for url_obj in start_urls:201 url = url_obj.get('url')202203 # Your scraping logic here204 await Actor.push_data({205 'url': url,206 'status': 'scraped',207 })208209 item_count += 1210 if max_items and item_count >= max_items:211 break212213 await Actor.set_status_message(f'Scraped {item_count} items')214215 if __name__ == '__main__':216 asyncio.run(main())217 ```2182197. **Python with Crawlee** (`src/main.py`):220 ```python221 import asyncio222 from apify import Actor223 from crawlee.playwright_crawler import PlaywrightCrawler, PlaywrightCrawlingContext224225 async def main():226 async with Actor:227 actor_input = await Actor.get_input() or {}228 start_urls = [url['url'] for url in actor_input.get('startUrls', [])]229230 crawler = PlaywrightCrawler(231 max_requests_per_crawl=actor_input.get('maxItems', 100),232 )233234 @crawler.router.default_handler235 async def request_handler(context: PlaywrightCrawlingContext):236 page = context.page237 title = await page.title()238239 await Actor.push_data({240 'url': context.request.url,241 'title': title,242 })243244 await context.enqueue_links()245246 await crawler.run(start_urls)247248 if __name__ == '__main__':249 asyncio.run(main())250 ```251252### Phase 4: Local Testing2532548. **Test locally**:255 ```bash256 # Run with default input257 apify run258259 # Run with purged storage (fresh start)260 apify run --purge261262 # View results263 cat storage/datasets/default/*.json264 ```2652669. **Validate input schema**:267 ```bash268 apify validate-schema .actor/input_schema.json269 ```270271### Phase 5: Deploy to Apify Platform27227310. **Push to Apify**:274 ```bash275 apify push276 ```277278 This uploads code, builds Docker image, and creates/updates the Actor.27928011. **Alternative: GitHub integration**:281 - Connect GitHub repo in Apify Console282 - Auto-builds on push to main branch283 - Better for collaboration and version control284285### Phase 6: Write README Documentation28628712. **Create compelling README.md**:288 ```markdown289 # My Web Scraper290291 Scrape data from websites efficiently with anti-blocking and proxy support.292293 ## Features294 - Fast parallel scraping with Crawlee295 - Automatic proxy rotation296 - Structured JSON/CSV output297 - Handles JavaScript-rendered pages298299 ## Input300301 | Parameter | Type | Required | Description |302 |-----------|------|----------|-------------|303 | startUrls | array | Yes | URLs to start scraping |304 | maxItems | integer | No | Max items (default: 100) |305306 ## Output307308 ```json309 {310 "url": "https://example.com/page",311 "title": "Page Title",312 "description": "Meta description",313 "scrapedAt": "2024-01-15T10:30:00Z"314 }315 ```316317 ## Usage318319 ### Via Apify Console320 1. Click "Start" on the Actor page321 2. Enter your start URLs322 3. Click "Run"323324 ### Via API325 ```bash326 curl -X POST "https://api.apify.com/v2/acts/YOUR_ACTOR/runs" \327 -H "Authorization: Bearer YOUR_TOKEN" \328 -H "Content-Type: application/json" \329 -d '{"startUrls": [{"url": "https://example.com"}]}'330 ```331332 ## Integrations333 - Zapier, Make, n8n support334 - Webhooks for notifications335 - Schedule runs via cron336337 ## Cost Estimation338 ~$X per 1,000 results using datacenter proxies.339 ```340341### Phase 7: Monetization Setup34234313. **Choose pricing model**:344345 **Option A: Pay-Per-Event (PPE)** - Most flexible, recommended346 - Charge for custom events (pages scraped, API calls, etc.)347 - You earn 80% revenue minus platform costs348 - AI/MCP compatible, priority store placement349350 **Option B: Pay-Per-Result (PPR)**351 - Charge per dataset item produced352 - Simpler to implement353 - You earn 80% revenue minus platform costs354355 **Option C: Rental**356 - Monthly subscription fee357 - Users pay their own platform costs358 - You earn 80% of rental fee35936014. **Implement PPE charging** (`.actor/pay_per_event.json`):361 ```json362 {363 "schemaVersion": 1,364 "events": [365 {366 "name": "apify-actor-start",367 "priceUsd": 0.00005,368 "description": "Actor initialization"369 },370 {371 "name": "page-scraped",372 "priceUsd": 0.002,373 "description": "Per page scraped"374 },375 {376 "name": "result-saved",377 "priceUsd": 0.001,378 "description": "Per result saved to dataset"379 }380 ]381 }382 ```38338415. **Charge events in code**:385 ```javascript386 // JavaScript - Option 1: Charge with pushData387 await Actor.pushData({ title, url }, 'result-saved');388389 // JavaScript - Option 2: Charge separately390 await Actor.charge({ eventName: 'page-scraped', count: 1 });391 ```392393 ```python394 # Python395 await Actor.push_data({'title': title, 'url': url}, 'result-saved')396 await Actor.charge(event_name='page-scraped', count=1)397 ```39839916. **Configure in Apify Console**:400 - Go to Actor -> Publication -> Monetization401 - Set up billing details for payouts402 - Choose pricing model via wizard403 - Set event prices404405### Phase 8: Publish to Store40640717. **Publication checklist**:408 - [ ] Comprehensive README with examples409 - [ ] Well-designed input schema with prefills410 - [ ] Clear title and description411 - [ ] Actor icon/image412 - [ ] Category selection413 - [ ] Test runs successful414 - [ ] Monetization configured41541618. **SEO optimization**:417 - Use keywords in title and description418 - Add "use cases" section419 - Include integration examples420 - Mention specific websites/platforms supported421422## Apify SDK Reference423424### Core Methods425426```javascript427// Initialize/Exit428await Actor.init();429await Actor.exit('Success message');430await Actor.fail('Error message');431432// Input/Output433const input = await Actor.getInput();434await Actor.pushData({ key: 'value' });435await Actor.setValue('key', 'value'); // Key-value store436const value = await Actor.getValue('key');437438// Storage439const dataset = await Actor.openDataset('name');440const kvStore = await Actor.openKeyValueStore('name');441const requestQueue = await Actor.openRequestQueue('name');442443// Platform features444const proxyConfig = await Actor.createProxyConfiguration(input.proxy);445await Actor.setStatusMessage('Processing...');446447// PPE charging448await Actor.charge({ eventName: 'my-event', count: 1 });449```450451### Crawlee Crawler Types452453| Crawler | Use Case | Speed | JS Rendering |454|---------|----------|-------|--------------|455| CheerioCrawler | Static HTML | Fastest | No |456| PlaywrightCrawler | Dynamic pages | Medium | Yes |457| PuppeteerCrawler | Dynamic pages | Medium | Yes |458| HttpCrawler | API calls | Fastest | No |459| JSDOMCrawler | Light DOM parsing | Fast | Partial |460461## All Available Templates462463### JavaScript464- `js-start` - Basic starter465- `js-crawlee-cheerio` - Cheerio crawler466- `js-crawlee-playwright-chrome` - Playwright browser467- `js-crawlee-puppeteer-chrome` - Puppeteer browser468- `js-crawlee-playwright-camoufox` - Camoufox (anti-detect)469- `js-langchain` - LangChain integration470- `js-langgraph-agent` - LangGraph agent471- `js-standby` - HTTP server (Standby mode)472- `js-empty` - Empty project473474### TypeScript475- `ts-start` - Basic starter476- `ts-crawlee-cheerio` - Cheerio crawler477- `ts-crawlee-playwright-chrome` - Playwright browser478- `ts-crawlee-puppeteer-chrome` - Puppeteer browser479- `ts-mcp-proxy` - MCP server proxy480- `ts-mcp-empty` - Empty MCP server481- `ts-standby` - HTTP server482- `ts-empty` - Empty project483484### Python485- `python-start` - Basic starter486- `python-crawlee-beautifulsoup` - BeautifulSoup crawler487- `python-crawlee-playwright` - Playwright crawler488- `python-crawlee-parsel` - Parsel crawler489- `python-playwright` - Playwright scraper490- `python-selenium` - Selenium scraper491- `python-scrapy` - Scrapy integration492- `python-crewai` - CrewAI agents493- `python-langgraph` - LangGraph agents494- `python-pydanticai` - PydanticAI495- `python-mcp-proxy` - MCP server proxy496- `python-standby` - HTTP server497- `python-empty` - Empty project498499## Pricing Strategy Tips5005011. **Research competitors** - Check similar Actors in Store5022. **Calculate costs** - Run tests, check Analytics tab5033. **Start competitive** - Most prices: $1-10 per 1,000 results5044. **Use PPE for flexibility** - Charge for what users actually use5055. **Offer free tier** - Low maxItems for testing506507## Maintenance Commitment508509Reserve ~2 hours/week for:510- Bug fixes and user support511- Keeping up with website changes512- Responding to Issues tab513- Improving documentation514515## Examples516517### Example 1: Simple Product Scraper518```javascript519import { Actor } from 'apify';520import { CheerioCrawler } from 'crawlee';521522await Actor.init();523const { startUrls } = await Actor.getInput();524525const crawler = new CheerioCrawler({526 async requestHandler({ $, request }) {527 const products = [];528 $('.product').each((_, el) => {529 products.push({530 name: $(el).find('.name').text(),531 price: $(el).find('.price').text(),532 url: request.url,533 });534 });535 await Actor.pushData(products);536 },537});538539await crawler.run(startUrls);540await Actor.exit();541```542543### Example 2: AI Agent Actor (Python with CrewAI)544```python545import asyncio546from apify import Actor547from crewai import Agent, Task, Crew548549async def main():550 async with Actor:551 input_data = await Actor.get_input()552 query = input_data.get('query')553554 researcher = Agent(555 role='Researcher',556 goal='Find accurate information',557 backstory='Expert researcher',558 )559560 task = Task(561 description=query,562 agent=researcher,563 )564565 crew = Crew(agents=[researcher], tasks=[task])566 result = crew.kickoff()567568 await Actor.push_data({'query': query, 'result': str(result)})569570if __name__ == '__main__':571 asyncio.run(main())572```573574## Resources575576- Apify SDK JS: https://docs.apify.com/sdk/js577- Apify SDK Python: https://docs.apify.com/sdk/python578- Crawlee: https://crawlee.dev579- Actor Templates: https://apify.com/templates580- Apify Academy: https://docs.apify.com/academy581- Store Optimization: https://docs.apify.com/academy/actor-marketing-playbook