{"id":18710687,"url":"https://github.com/apify/actor-whitepaper","last_synced_at":"2025-11-03T16:28:40.696Z","repository":{"id":256488550,"uuid":"247443600","full_name":"apify/actor-whitepaper","owner":"apify","description":"This whitepaper describes a new concept for building serverless microapps called Actors, which are easy to develop, share, integrate, and build upon. Actors are a reincarnation of the UNIX philosophy for programs running in the cloud.","archived":false,"fork":false,"pushed_at":"2025-05-06T11:08:12.000Z","size":3170,"stargazers_count":67,"open_issues_count":12,"forks_count":1,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-06-30T07:06:12.036Z","etag":null,"topics":["agents","automation","node-js","python","scraping","serverless"],"latest_commit_sha":null,"homepage":"https://whitepaper.actor","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/apify.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-03-15T10:22:46.000Z","updated_at":"2025-06-25T01:36:59.000Z","dependencies_parsed_at":"2024-11-07T12:38:28.337Z","dependency_job_id":"8f861a3f-e7bf-42be-9b4f-fe261d2c11d7","html_url":"https://github.com/apify/actor-whitepaper","commit_stats":null,"previous_names":["apify/actor-whitepaper"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/apify/actor-whitepaper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apify%2Factor-whitepaper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apify%2Factor-whitepaper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apify%2Factor-whitepaper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apify%2Factor-whitepaper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/apify","download_url":"https://codeload.github.com/apify/actor-whitepaper/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apify%2Factor-whitepaper/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262925001,"owners_count":23385462,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agents","automation","node-js","python","scraping","serverless"],"created_at":"2024-11-07T12:35:17.245Z","updated_at":"2025-11-03T16:28:40.686Z","avatar_url":"https://github.com/apify.png","language":"Python","readme":"# The Web Actor Programming Model Whitepaper\n\n**This whitepaper describes a new concept for building serverless microapps called **_Actors_**,\nwhich are easy to develop, share, integrate, and build upon.\nActors are a reincarnation of the UNIX philosophy\nfor programs running in the cloud.**\n\nBy [Jan Čurn](https://apify.com/jancurn),\n[Marek Trunkát](https://apify.com/mtrunkat),\n[Ondra Urban](https://apify.com/mnmkng), and the entire Apify team.\n\n**Version 0.999 (February 2025)**\n\n## Contents\n\n\u003c!-- toc --\u003e\n\n- [Introduction](#introduction)\n  * [Background](#background)\n  * [Overview](#overview)\n  * [Apify platform](#apify-platform)\n- [Basic concepts](#basic-concepts)\n  * [Input](#input)\n  * [Run environment](#run-environment)\n  * [Output](#output)\n  * [Storage](#storage)\n  * [Integrations](#integrations)\n  * [What Actors are not](#what-actors-are-not)\n- [Philosophy](#philosophy)\n  * [UNIX programs vs. Actors](#unix-programs-vs-actors)\n  * [Design principles](#design-principles)\n  * [Relation to the Actor model](#relation-to-the-actor-model)\n  * [Why the name \"Actor\"](#why-the-name-actor)\n- [Installation and setup](#installation-and-setup)\n  * [Running on the Apify platform](#running-on-the-apify-platform)\n  * [Node.js](#nodejs)\n  * [Python](#python)\n  * [Command-line interface (CLI)](#command-line-interface-cli)\n- [Actor programming interface](#actor-programming-interface)\n  * [Initialization](#initialization)\n  * [Get input](#get-input)\n  * [Key-value store access](#key-value-store-access)\n  * [Push results to dataset](#push-results-to-dataset)\n  * [Exit Actor](#exit-actor)\n  * [Environment variables](#environment-variables)\n  * [Actor status](#actor-status)\n  * [System events](#system-events)\n  * [Get memory information](#get-memory-information)\n  * [Start another Actor](#start-another-actor)\n  * [Metamorph](#metamorph)\n  * [Attach webhook to an Actor run](#attach-webhook-to-an-actor-run)\n  * [Abort another Actor](#abort-another-actor)\n  * [Reboot an Actor](#reboot-an-actor)\n  * [Actor web server](#actor-web-server)\n  * [Standby mode](#standby-mode)\n  * [Migration to another server](#migration-to-another-server)\n  * [Charging money](#charging-money)\n- [Actor definition files](#actor-definition-files)\n  * [Actor file](#actor-file)\n  * [Dockerfile](#dockerfile)\n  * [README](#readme)\n  * [Input schema file](#input-schema-file)\n  * [Output schema file](#output-schema-file)\n  * [Storage schema files](#storage-schema-files)\n  * [Backward compatibility](#backward-compatibility)\n- [Development](#development)\n  * [Local development](#local-development)\n  * [Deployment to Apify platform](#deployment-to-apify-platform)\n  * [Continuous integration and delivery](#continuous-integration-and-delivery)\n  * [Actorizing existing code](#actorizing-existing-code)\n- [Sharing and publishing](#sharing-and-publishing)\n  * [Monetization](#monetization)\n- [Future work](#future-work)\n- [Links](#links)\n\n\u003c!-- tocstop --\u003e\n\n## Introduction\n\nThis whitepaper introduces **_Actors_**,\na new language-agnostic model for building general-purpose\nweb computing and automation programs (also known as agents, functions, or apps).\nThe main goal for Actors is to make it easy for developers to build and ship reusable\nsoftware tools, which are easy to run, integrate, and build upon.\nActors are useful for building\nweb scrapers, crawlers, automations, and AI agents.\n\n### Background\n\nActors were first introduced by [Apify](https://apify.com/) in late 2017,\nas a way to easily build, package, and ship web scraping and web automation jobs to customers.\nOver the years, Apify has continued to develop the concept and applied\nit successfully to thousands of real-world use cases in many business areas,\nwell beyond the domain of web scraping.\n\nBuilding on this experience,\nwe're releasing this whitepaper to introduce the philosophy of Actors\nto other developers and receive your feedback on it.\nWe aim to establish the Actor programming model as an open standard,\nwhich will help the community to more effectively\nbuild and ship reusable software automation tools,\nas well as encourage new implementations of the model in other programming languages.\n\nThe goal of this whitepaper is to be the North Star that shows what the\nActor programming model is and what operations it should support.\n**But this document is not an official specification.**\nThe specification will be an OpenAPI schema of the Actor system interface,\nto enable new independent implementations of both the client libraries and backend systems. This is currently a work in progress.\n\nCurrently, the most complete implementation of the Actor model is provided\nby the Apify platform, with SDKs for\n[Node.js](https://sdk.apify.com/) and\n[Python](https://pypi.org/project/apify/),\nand a [command-line interface (CLI)](https://docs.apify.com/cli).\nBeware that the frameworks might not yet implement all the features of the Actor programming model\ndescribed in this whitepaper.\n\n### Overview\n\nActors are serverless programs that run in the cloud.\nThey can perform anything from simple actions such as\nfilling out a web form or sending an email,\nto complex operations such as crawling an entire website,\nor removing duplicates from a large dataset.\nActors can persist their state and be restarted, and thus they can\nrun as short or as long as necessary, from seconds to hours, even infinitely.\n\nBasically, Actors are programs packaged as Docker images,\nwhich accept a well-defined JSON input, perform\nan action, and optionally produce a well-defined JSON output.\n\nActors have the following elements:\n\n- **Dockerfile** which specifies where the Actor's source code is,\n  how to build it, and run it.\n- **Documentation** in a form of a README.md file.\n- **Input and output schemas** that describe what input the Actor requires,\n  and what results it produces.\n- Access to an out-of-the-box **storage system** for Actor data, results, and files.\n- **Metadata** such as the Actor name, description, author, and version.\n\nThe documentation and the input/output schemas make it possible for people to easily understand what the Actor does,\nenter the required inputs both in user interface or API,\nand integrate the results of the Actor into their other workflows.\nActors can easily call and interact with each other, enabling the building of more complex\nsystems on top of simple ones.\n\n\u003c!-- ASTRO: \u003cDiagram horizontal={illuDiagramHoriz} vertical={illuDiagramVert} alt=\"Actor drawing\" /\u003e --\u003e\n\n![Apify Actor diagram](./img/apify-actor-drawing.png)\n\n\u003c!-- Image sources: \n  https://docs.google.com/presentation/d/1nDgrI0p2r8ouP_t_Wn02aTllP8_Std-kRuIbO8QLE7M/edit\n  https://www.figma.com/design/6vbmKvB6oY3b3mTN0oAscE/Actor-Whitepaper-Diagrams-and-Presentations?node-id=0-1\u0026p=f\u0026t=JwAJfru2GjdQBpBV-11\n--\u003e\n\n### Apify platform\n\nActors can be published\non the [Apify platform](https://apify.com/store),\nwhich automatically generates a rich website with documentation based on the README\nand a practical user interface, in order to encourage people to try the Actor right away.\nThe Apify platform takes care of securely hosting the Actor's Docker containers\nand scaling the computing, storage and network resources as needed,\nso neither Actor developers nor the users need to deal with the infrastructure.\nIt just works.\n\nThe Apify platform provides an open API, cron-style scheduler, webhooks\nand [integrations](https://apify.com/integrations)\nto services such as Zapier or Make, which make it easy for users\nto integrate Actors into their existing workflows. Additionally, the Actor developers\ncan set a price tag for the usage of their Actors, and thus earn income\nand have an incentive to keep developing and improving the Actor for the users.\nFor details, see [Monetization](#monetization).\n\n## Basic concepts\n\nThis section describes core features of Actors, what they are good for,\nand how Actors differ from other serverless computing systems.\n\n### Input\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"Each Actor accepts an input object, which tells it what it should do.\"\n    position=\"content\"\n    image={illuBasicConceptsInput}\n    noCaption\n/\u003e\n--\u003e\n\nEach Actor accepts an **input object**, which tells it what it should do.\nThe object is passed in JSON format, and its properties have\na similar role as command-line arguments when running a program in a UNIX-like operating system.\n\nFor example, an input object for an Actor `bob/screenshotter` could look like this:\n\n```json\n{\n  \"url\": \"https://www.example.com\",\n  \"width\": 800\n}\n```\n\nThe input object represents a standardized way for the caller to control the Actor's activity,\nwhether starting it using API, user interface, CLI, or scheduler.\nThe Actor can access the value of the input object using the [Get input](#get-input) function.\n\nIn order to specify what kind of input object an Actor expects,\nthe Actor developer can define an [Input schema file](#input-schema-file).\n\nThe input schema is used by the system to generate user interface, API examples,\nand simplify integration with external systems.\n\n#### Example of auto-generated Actor input UI\n\n![Screenshot Taker Input UI](./img/screenshot-taker-input.png)\n\n\u003c!-- ASTRO: \u003cPicture src={illuTakerInput} alt=\"Taker input\" formats={['avif', 'webp']} /\u003e --\u003e\n\n### Run environment\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"The Actors run within an isolated Docker container\"\n    position=\"right\"\n    image={illuBasicConceptsRunEnvironment}\n/\u003e\n--\u003e\n\nActors run within an isolated Docker container with access to local file system and network,\nand they can perform arbitrary computing activity or call external APIs.\nThe **standard output** of the Actor's program (stdout and stderr) is printed out and logged,\nwhich is useful for development and debugging.\n\nTo inform the users about the progress, the Actors might set a [status message](#actor-status),\nwhich is then displayed in the user interface and also available via API.\n\nA running Actor can also launch a [web server](#actor-web-server),\nwhich is assigned a unique local or public URL to receive HTTP requests. For example,\nthis is useful for messaging and interaction between Actors, for running request-response REST APIs, or\nproviding a full-featured website.\n\nActors can store their working data or results into specialized **storages**\ncalled [Key-value store](#key-value-store) and [Dataset](#dataset) storages,\nfrom which they can be easily exported using API or integrated in other Actors.\n\n### Output\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"The Actors can generate an output object, which is a standardized way to display, consume, and integrate Actors' results.\"\n    position=\"right\"\n    image={illuBasicConceptsOutput}\n/\u003e\n--\u003e\n\nWhile the input object provides a standardized way to invoke Actors,\nActors can also generate an **output object**, which is a standardized way to display, consume, and integrate\nActors' results.\n\nActor results are typically fully available only after the Actor run finishes,\nbut the consumers of the results might want to access partial results during the run.\nTherefore, Actors don't generate the output object in their code, but they\ndefine an [Output schema file](#output-schema-file), which contains\ninstruction how to generate such output object automatically.\n\nYou can define how the Actor output looks using the [Output schema file](#output-schema-file).\nThe system uses this information to automatically generate an immutable JSON file,\nwhich tells users where to find the results produced by the Actor.\nThe output object is stored by the system\nto the Actor run object under the `output` property, and returned via API immediately when\nthe Actor is started, without the need to wait for it to finish or generate the actual results.\nThis is useful to automatically generate UI previews of the results, API examples,\nand integrations.\n\n\u003cdiv class=\"clear-both\" /\u003e\n\nThe output object is similar to the input object, as it contains properties and values.\nFor example, for the `bob/screenshotter` Actor, the output object could look like this:\n\n```jsonc\n{\n  \"screenshotUrl\": \"https://api.apify.com/v2/key-value-stores/skgGkFLQpax59AsFD/records/screenshot.jpg\",\n  \"productImages\": \"https://api.apify.com/v2/key-value-stores/skgGkFLQpax59AsFD/records/product*.jpg\",\n  \"productDetails\": \"https://api.apify.com/datasets/9dFknjkxxGkspwWd/records?fields=url,name\",\n  \"productExplorer\": \"https://bob--screenshotter.apify.actor/product-explorer\",\n  // or this with live view\n  \"productExplorer\": \"https://13413434.runs.apify.net/product-explorer\"\n}\n\n```\n\n### Storage\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"The Actor system provides two specialized storages that can be used by Actors for storing files and results: Key-value store and Dataset\"\n    position=\"content\"\n    image={illuBasicConceptsStorage}\n    noCaption\n/\u003e\n--\u003e\n\nThe Actor system provides two specialized storages that can be used by Actors for storing files and results:\n**key-value store** and **dataset**, respectively. For each Actor run,\nthe system automatically creates so-called **default storages** of both these types\nin empty state and makes them readily available for the Actor.\n\nAlternatively, a caller can request reusing existing storage when starting a new Actor run.\nThis is similar to redirecting standard input in UNIX,\nand it is useful if you want an Actor to operate on an existing key-value store or dataset instead of creating a new one.\n\u003c!-- TODO: The above feature is not implemented yet --\u003e\n\nBesides these so-called **default storages**, which are created or linked automatically, Actors are free to create new storages or\naccess existing ones, either by ID or a name that can be set for them (e.g. `bob/screenshots`).\nThe [input schema file](#input-schema-file) and [output schema file](#output-schema-file) provide special support for referencing these storages,\nin order to simplify linking an output of one Actor to an input of another.\nThe storages are also accessible through an API and SDK externally, for example,\nto download results when the Actor finishes.\n\nNote that Actors are free to access any other external storage system through a third-party API, e.g.\nan SQL database or a vector database.\n\n#### Key-value store\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"The key-value store is a simple data storage that is used for saving and reading files or data records\"\n    position=\"right\"\n    image={illuBasicConceptsStorageKeyValueStore}\n/\u003e\n--\u003e\n\nThe key-value store is a simple data storage that is used for saving and reading\nfiles or data records. The records are represented by a unique text key and the data associated with a MIME content type.\nKey-value stores are ideal for saving things like screenshots, web pages, PDFs, or to persist the state of Actors e.g. as a JSON file.\n\nEach Actor run is associated with a default empty key-value store, which is created exclusively for the run,\nor alternatively with an existing key-value store if requested by the user on Actor start.\nThe [Actor input](#input) is stored as JSON file into the default key-value store under the key defined by\nthe `ACTOR_INPUT_KEY` environment variable (usually `INPUT`).\nThe Actor can read this input object using the [Get input](#get-input) function.\n\nAn Actor can read and write records to key-value stores using the API. For details,\nsee [Key-value store access](#key-value-store-access).\n\nAn Actor can define a schema for the key-value store to ensure files stored in it conform to certain rules.\nFor details, see [Storage schema files](#storage-schema-files).\n\n#### Dataset\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"The dataset is an append-only storage that allows you to store a series of data objects such as results from web scraping, crawling, or data processing jobs.\"\n    position=\"right\"\n    image={illuBasicConceptsStorageDataset}\n/\u003e\n--\u003e\n\nThe dataset is an append-only storage that allows you to store a series of data objects\nsuch as results from web scraping, crawling, or data processing jobs.\nYou or your users can then export the dataset to formats such as JSON, CSV, XML, RSS, Excel, or HTML.\n\nThe dataset represents a store for structured data where each object stored has the same attributes,\nsuch as online store products or real estate offers. You can imagine it as a table, where each object is\na row and its attributes are columns. Dataset is an append-only storage — you can only add new records to\nit, but you cannot modify or remove existing records. Typically, it is used to store an array or collection of results,\nsuch as a list of products or web pages.\n\nAn Actor can define a schema for the Dataset to ensure objects stored in it conform to certain rules.\nFor details, see [Storage schema files](#storage-schema-files).\n\n### Integrations\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"Actors are designed for interoperability. Thanks to the input and output schemas, it's easy to connect Actors with external systems, be it directly via REST API, Node.js or Python clients, CLI, or no-code automations.\"\n    position=\"content\"\n    image={illuBasicConceptsIntegrations}\n    noCaption\n/\u003e\n--\u003e\n\n**Actors are designed for interoperability.** Thanks to the input and output\nschemas, it easy to connect Actors with external systems,\nbe it directly via REST API, Node.js or Python clients, CLI, or no-code automations.\nFrom the schema files, the system can automatically generate API documentation, OpenAPI specification,\nand validate inputs and outputs, simplifying their integrations to any other systems.\n\nFurthermore, Actors can interact with themselves,\nfor example [start another Actors](#start-another-actor),\nattach [Webhooks](#attach-webhook-to-an-actor-run) to process the results,\nor [Metamorph](#metamorph) into another Actor to have it finish the work.\n\n### What Actors are not\n\nActors are best suited for compute operations that take an input, perform an isolated job for a user,\nand potentially produce some output.\n\nFor long-running jobs, Actor execution might be migrated\nfrom server to another server, making it unsuitable for running dependable storage workloads\nsuch as SQL databases.\n\nAs Actors are based on Docker, it takes a certain amount of time to spin up the container\nand launch its main process. Doing this for every small HTTP transaction (e.g. API call) is not efficient,\neven for highly-optimized Docker images. However, Actor [Standby mode](#standby-mode) enables\nan Actor to run as a web server, to more effectively process small API requests.\n\n## Philosophy\n\nActors are inspired by the **[UNIX philosophy](https://en.wikipedia.org/wiki/Unix_philosophy)** from the 1970s, adapted to the age of the cloud:\n\n1. **Make each program do one thing well**. To do a new job, build afresh rather than complicate old programs by adding new “features”.\n2. Expect the **output of every program to become the input to another, as yet unknown, program**. Don’t clutter output with extraneous information. Avoid stringently columnar or binary input formats. Don’t insist on interactive input.\n3. Design and build software, even operating systems, to be **tried early**, ideally within weeks. Don’t hesitate to throw away the clumsy parts and rebuild them.\n4. **Use tools in preference to unskilled help** to lighten a programming task, even if you have to detour to build the tools and expect to throw some of them out after you’ve finished using them.\n\nThe UNIX philosophy is arguably one of the most important software engineering paradigms\nwhich, together with other favorable design choices of UNIX operating systems,\nushered in the computer and internet revolution.\nBy combining smaller parts\nthat can be developed and used independently (programs),\nit suddenly became possible to build, manage and gradually evolve ever more complex computing systems.\nEven today's modern mobile devices are effectively UNIX-based machines that run a lot of programs\ninteracting with each other, and provide a terminal\nwhich looks very much like early UNIX terminals. In fact, terminal is just another program.\n\nUNIX-style programs represent a great way to package software for usage\non a local computer. The programs can easily be used stand-alone,\nbut also in combination and in scripts\nin order to perform much more complex tasks than an individual program ever could,\nwhich in turn can be packaged as new programs.\n\nThe idea of Actors is to bring the benefits of UNIX-style programs\nfrom a local computer to a cloud environment\nwhere programs run on multiple computers\ncommunicating over a network that is subject to latency and partitioning,\nthere is no global atomic filesystem,\nand where programs are invoked via API calls rather than system calls.\n\nEach Actor should do just one thing and do it well.\nActors can be used stand-alone, as well as combined or scripted into more complex\nsystems, which in turn can become new Actors.\nActors provide a simple user interface and documentation to help users interact with them.\n\n### UNIX programs vs. Actors\n\nThe following table shows the equivalents of key concepts of UNIX programs and Actors.\n\n| UNIX programs              | Actors                                                                                                                             |\n|----------------------------|------------------------------------------------------------------------------------------------------------------------------------|\n| Command-line options       | [Input object](#get-input)                                                                                                         |\n| Read stdin                 | No direct equivalent, you can [read from a dataset](#dataset) specified in the input.                                              |\n| Write to stdout           | [Push results to dataset](#push-results-to-dataset), set [Actor status](#actor-status)                                             |\n| Write to stderr           | No direct equivalent, you can write errors to log, set error status message, or push failed dataset items into an \"error\" dataset. |\n| File system               | [Key-value store](#key-value-store-access)                                                                                         |\n| Process identifier (PID)   | Actor run ID                                                                                                                       |\n| Process exit code          | [Actor exit code](#exit-actor)                                                                                                     |\n\n### Design principles\n\n- Each Actor should do just one thing, and do it well.\n- Optimize for the users of the Actors, help them understand what the Actor does, easily run it, and integrate.\n- Also optimize for interoperability, to make it ever easier to connect Actors with other systems.\n  Expect objects you work with to contain additional not-yet-known fields.\n- Keep the API as simple as possible and write great documentation, so that Actors can be built and used by \u003e90% of software developers,\n  even ones using no-code tools (yes, that's also software development!).\n\n### Relation to the Actor model\n\nNote that Actors are only loosely related to\nthe **Actor model** in computer science introduced by the 1973 paper by Carl Hewitt.\nAccording to [Wikipedia](https://en.wikipedia.org/wiki/Actor_model):\n\n\u003e The Actor model in computer science is a mathematical model of concurrent computation\n\u003e that treats Actor as the universal primitive of concurrent computation.\n\u003e In response to a message it receives, an Actor can: make local decisions,\n\u003e create more Actors, send more messages, and determine how to respond to the\n\u003e next message received. Actors may modify their own private state,\n\u003e but can only affect each other indirectly through messaging\n\u003e (removing the need for lock-based synchronization).\n\nWhile the theoretical Actor model is conceptually very similar to \"our\" Actor programming model,\nthis similarity is rather coincidental.\nOur primary focus was always on practical software engineering utility, not an\nimplementation of a formal mathematical model.\n\nFor example, our Actors\ndo not provide any standard message passing mechanism, but they can communicate together\ndirectly via HTTP requests (see [Actor web server](#actor-web-server)),\nmanipulate each other's operation via the Apify platform API (e.g. abort another Actor),\nor affect each other by sharing some internal state or storage.\nActors do not have any formal restrictions,\nand they can access whichever external systems they want,\nthus going beyond the formal mathematical Actor model.\n\n### Why the name \"Actor\"\n\nIn movies and theater, an _actor_ is someone who gets a script\nand plays a role according to that script.\nOur Actors also perform an act on someone's behalf, using a provided script.\nThey work well with Puppeteers and Playwrights.\n\nTo make it clear that Actors are not people, the letter \"A\" is capitalized.\n\n\u003c!-- ASTRO: \u003cIllustration description=\"Actors\" position=\"content\" image={illuPhilosophyWhyTheName} noCaption /\u003e --\u003e\n\n## Installation and setup\n\nBelow are the steps to start building Actors in various languages and environments.\n\n### Running on the Apify platform\n\nYou can develop and run Actors in [Apify Console](https://console.apify.com/actors) without\ninstalling any software locally. Just create a free Apify account, and start building Actors\nin an online IDE.\n\n\u003c!-- ASTRO: \u003cCodeSwitcher\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Node.js\"\u003e --\u003e\n\n### Node.js\n\nThe most complete implementation of the Actor system is provided by the Apify SDK for Node.js,\nvia the [apify](https://www.npmjs.com/package/apify) NPM package. The package contains everything\nthat you need to start building Actors locally.\nYou can install it to your Node.js project by running:\n\n```bash\n$ npm install apify\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Python\"\u003e --\u003e\n\n### Python\n\nTo build Actors in Python, simply install the Apify SDK for Python,\nvia the [apify](https://pypi.org/project/apify/) PyPi package\ninto your project:\n\n```bash\n$ pip3 install apify\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"CLI\"\u003e --\u003e\n\n### Command-line interface (CLI)\n\nFor local development of Actors and management of the Apify platform,\nit is handy to install the Apify CLI.\nYou can install it with:\n\n```bash\n$ brew install apify-cli\n```\n\nor via the [apify-cli](https://www.npmjs.com/package/apify-cli) Node.js package:\n\n```bash\n$ npm install -g apify-cli\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003c/CodeSwitcher\u003e --\u003e\n\nYou can confirm the installation succeeded and log in to the Apify platform by running:\n\n```bash\n$ apify login\n```\n\nThe Apify CLI provides two commands: `apify` and `actor`.\n\n`apify` command lets you interact with the Apify platform, for example run an Actor,\npush deployment of an Actor to cloud, or access storages. For details, see [Local development](#local-development).\n\n`actor` command is to be used from within an Actor in the runtime, to implement the Actors functionality in a shell script.\n   For details, see [Actorizing existing code](#actorizing-existing-code).\n\nTo get help for a specific command, run:\n\n ```bash\n$ apify help \u003ccommand\u003e\n$ actor help \u003ccommand\u003e\n```\n\n## Actor programming interface\n\nThe commands described in this section are expected to be called from within a context\nof a running Actor, both in local environment or on the Apify platform.\n\nThe Actor runtime system passes the context via [environment variables](#environment-variables),\nsuch as `APIFY_TOKEN` or `ACTOR_RUN_ID`, which is used by the SDK or CLI to interact with the runtime.\n\n### Initialization\n\nThe SDKs provide convenience methods to initialize the Actor and handle its results.\nDuring initialization, the SDK loads environment variables, checks the configuration, prepares to receive system events,\nand optionally purges previous state from local storage.\n\n\u003cdiv class=\"clear-both\" /\u003e\n\n\u003c!-- ASTRO: \u003cCodeSwitcher\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Node.js\"\u003e --\u003e\n\n#### Node.js\n\nIn Node.js the Actor is initialized by calling the `init()` method. It should be paired with an `exit()` method\nwhich terminates the Actor. Use of `exit()` is not required, but recommended. For more information go to [Exit Actor](#exit-actor).\n\n```js\nimport { Actor } from 'apify';\n\nawait Actor.init();\n\nconst input = await Actor.getInput();\nconsole.log(input);\n\nawait Actor.exit();\n```\n\nAn alternative way of initializing the Actor is with a `main()` function. This is useful in environments where the latest JavaScript\nsyntax and top level awaits are not supported. The main function is only syntax-sugar for `init()` and `exit()`. It will call `init()` before it executes its callback and `exit()` after the callback resolves.\n\n```js\nimport { Actor } from 'apify';\n\nActor.main(async () =\u003e {\n  const input = await Actor.getInput();\n  // ...\n});\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Python\"\u003e --\u003e\n\n#### Python\n\n```python\nimport asyncio\nfrom apify import Actor\n\nasync def main():\n  async with Actor:\n    input = await Actor.get_input()\n    print(input)\n\nasyncio.run(main())\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"CLI\"\u003e --\u003e\n\n#### CLI\n\nNo initialization needed, the process exit terminates the Actor, with the process status code\ndetermining whether it succeeded or failed.\n\n```bash\n$ actor set-status-message \"My work is done, friend\"\n$ exit 0\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"UNIX equivalent\"\u003e --\u003e\n\n#### UNIX equivalent\n\n```c\nint main (int argc, char *argv[]) {\n  ...\n}\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003c/CodeSwitcher\u003e --\u003e\n\n### Get input\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"The input object is passed by the user and stored in the Actor's default key-value store. The input is an object with properties. If the Actor defines the input schema, the input object is guaranteed to conform to it.\"\n    position=\"right\"\n    image={illuAPIGetInput}\n    noCaption\n/\u003e\n--\u003e\n\nGet access to the Actor input object passed by the user.\nIt is parsed from a JSON file, which is stored by the system in the Actor's default key-value store,\nUsually the file is called `INPUT`, but the exact key is defined in the `ACTOR_INPUT_KEY` [environment variable](#environment-variables).\n\nThe input is an object with properties.\nIf the Actor defines the input schema, the input object is guaranteed to conform to it.\nFor details, see [Input](#input).\n\n\u003cdiv class=\"clear-both\" /\u003e\n\n\u003c!-- ASTRO: \u003cCodeSwitcher\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Node.js\"\u003e --\u003e\n\n#### Node.js\n\n```js\nconst input = await Actor.getInput();\nconsole.log(input);\n\n// prints: { \"option1\": \"aaa\", \"option2\": 456 }\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Python\"\u003e --\u003e\n\n#### Python\n\n```python\ninput = Actor.get_input()\nprint(input)\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"CLI\"\u003e --\u003e\n\n#### CLI\n\n```bash\n# Emits a JSON object, which can be parsed e.g. using the \"jq\" tool\n$ actor get-input | jq\n\n\u003e { \"option1\": \"aaa\", \"option2\": 456 }\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"UNIX equivalent\"\u003e --\u003e\n\n#### UNIX equivalent\n\n```bash\n$ command --option1=aaa --option2=bbb\n```\n\n```c\nint main (int argc, char *argv[]) {}\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003c/CodeSwitcher\u003e --\u003e\n\n### Key-value store access\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"Write and read arbitrary files using a storage called Key-value store. When an Actor starts, by default it is associated with a newly-created key-value store, which only contains one file with input of the Actor.\"\n    position=\"right\"\n    image={illuAPIKeyValueStoreAccess}\n    noCaption\n/\u003e\n--\u003e\n\nWrite and read arbitrary files using a storage\ncalled [Key-value store](https://sdk.apify.com/docs/api/key-value-store).\nWhen an Actor starts, by default it is associated with a newly-created key-value store,\nwhich only contains one file with the input of the Actor (see [Get input](#get-input)).\n\nThe user can override this behavior and specify another key-value store or input key\nwhen running the Actor.\n\n\u003cdiv class=\"clear-both\" /\u003e\n\n\u003c!-- ASTRO: \u003cCodeSwitcher\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Node.js\"\u003e --\u003e\n\n#### Node.js\n\n```js\n// Save objects to the default key-value store\nawait Actor.setValue('my_state', { something: 123 }); //  (stringified to JSON)\nawait Actor.setValue('screenshot.png', buffer, { contentType: 'image/png' });\n\n// Get record from the default key-value store, automatically parsed from JSON\nconst value = await Actor.getValue('my_state');\n\n// Access another key-value store by its name\nconst store = await Actor.openKeyValueStore('screenshots-store');\nconst imageBuffer = await store.getValue('screenshot.png');\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Python\"\u003e --\u003e\n\n#### Python\n\n```python\n# Save object to store (stringified to JSON)\nawait Actor.set_value('my-state', { 'something': 123 })\n\n# Save binary file to store with content type\nawait Actor.set_value('screenshot', buffer, content_type='image/png')\n\n# Get object from store (automatically parsed from JSON)\nstate = await Actor.get_value('my-state')\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"UNIX\"\u003e --\u003e\n\n#### UNIX\n\n```bash\n$ echo \"hello world\" \u003e file.txt\n$ cat file.txt\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003c/CodeSwitcher\u003e --\u003e\n\n### Push results to dataset\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"Larger results can be saved to append-only object storage called Dataset. When an Actor starts, by default it is associated with a newly-created empty default dataset. The Actor can create additional datasets or access existing datasets created by other Actors, and use those as needed.\"\n    position=\"right\"\n    image={illuAPIPush}\n    noCaption\n/\u003e\n--\u003e\n\nLarger results can be saved to append-only object storage called [Dataset](https://sdk.apify.com/docs/api/dataset).\nWhen an Actor starts, by default it is associated with a newly-created empty default dataset.\nThe Actor can create additional datasets or access existing datasets created by other Actors,\nand use those as needed.\n\nNote that datasets can optionally be equipped with schema that ensures only certain kinds\nof objects are stored in them. See [Dataset schema file](./pages/DATASET_SCHEMA.md) for more details.\n\n\u003cdiv class=\"clear-both\" /\u003e\n\n\u003c!-- ASTRO: \u003cCodeSwitcher\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Node.js\"\u003e --\u003e\n\n#### Node.js\n\n```js\n// Append result object to the default dataset associated with the run\nawait Actor.pushData({\n    someResult: 123,\n});\n\n// Append result object to a specific named dataset\nconst dataset = await Actor.openDataset('bob/poll-results-2019');\nawait dataset.pushData({ someResult: 123 });\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Python\"\u003e --\u003e\n\n#### Python\n\n```python\n# Append result object to the default dataset associated with the run\nawait Actor.push_data({ 'some_result': 123 })\n\n# Append result object to a specific named dataset\ndataset = await Actor.open_dataset('bob/poll-results-2019')\nawait dataset.push_data({ 'some_result': 123 })\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"CLI\"\u003e --\u003e\n\n#### CLI\n\n```bash\n# Push data to default dataset, in JSON format\n$ echo '{ \"someResult\": 123 }' | actor push-data --json\n$ actor push-data --json='{ \"someResult\": 123 }'\n$ actor push-data --json=@result.json\n\n# Push data to default dataset, in text format\n$ echo \"someResult=123\" | actor push-data\n$ actor push-data someResult=123\n\n# Push to a specific dataset in the cloud\n$ actor push-data --dataset=bob/election-data someResult=123\n\n# Push to dataset on local system\n$ actor push-data --dataset=./my_dataset someResult=123\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"UNIX equivalent\"\u003e --\u003e\n\n#### UNIX equivalent\n\n```c\nprintf(\"Hello world\\tColum 2\\tColumn 3\");\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003c/CodeSwitcher\u003e --\u003e\n\n### Exit Actor\n\nWhen the main Actor process exits and the Docker container stops running,\nthe Actor run is considered finished and the process exit code is used to determine\nwhether the Actor has succeeded (exit code `0` leads to status `SUCCEEDED`)\nor failed (exit code not equal to `0` leads to status `FAILED`).\n\nIn the event of a non-zero exit code, the system automatically sets the Actor [status message](#actor-status)\nto something like `Actor exited with code 0`, and it might attempt\nto restart the Actor to recover from the error, depending on the system and Actor configuration.\n\nA preferred way to exit an Actor intentionally is using the `exit` or `fail` functions in SDK, as\nshown below. This has several advantages:\n\n- You can provide a custom status message for users to tell them what the Actor achieved,\n  or why it failed and how they can fix it. This greatly improves user experience.\n- When using `fail` to fail the Actor, the system considers the error permanent  and will not attempt to restart the Actor.\n- The SDK emits the `exit` event, which can be listened to and used by various\n  components of the Actor to perform a cleanup, persist state, etc.\n  Note that the caller of exit can specify how long should the system wait for all `exit`\n  event handlers to complete before closing the process, using the `timeoutSecs` option.\n  For details, see [System Events](#system-events).\n\n\u003c!-- ASTRO: \u003cCodeSwitcher\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Node.js\"\u003e --\u003e\n\n#### Node.js\n\n```js\n// Actor will finish with 'SUCCEEDED' status\nawait Actor.exit('Succeeded, crawled 50 pages');\n\n// Exit right away without calling `exit` handlers at all\nawait Actor.exit('Done right now', { timeoutSecs: 0 });\n\n// Actor will finish with 'FAILED' status \nawait Actor.exit('Could not finish the crawl, try increasing memory', { exitCode: 1 });\n\n// ... or nicer way using this syntactic sugar:\nawait Actor.fail('Could not finish the crawl, try increasing memory');\n\n// Register a handler to be called on exit.\n// Note that the handler has `timeoutSecs` to finish its job\nActor.on('exit', ({ statusMessage, exitCode, timeoutSecs }) =\u003e {\n    // Perform cleanup...\n})\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Python\"\u003e --\u003e\n\n#### Python\n\n```python\n# Actor will finish in 'SUCCEEDED' state\nawait Actor.exit('Generated 14 screenshots')\n\n# Actor will finish in 'FAILED' state\nawait Actor.exit('Could not finish the crawl, try increasing memory', exit_code=1)\n# ... or nicer way using this syntactic sugar:\nawait Actor.fail('Could not finish the crawl, try increasing memory');\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"CLI\"\u003e --\u003e\n\n#### CLI\n\n```bash\n# Actor will finish in 'SUCCEEDED' state\n$ actor exit\n$ actor exit --message \"Email sent\"\n\n# Actor will finish in 'FAILED' state\n$ actor exit --code=1 --message \"Couldn't fetch the URL\"\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"UNIX equivalent\"\u003e --\u003e\n\n#### UNIX equivalent\n\n```c\nexit(1);\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003c/CodeSwitcher\u003e --\u003e\n\n### Environment variables\n\nActors have access to standard process environment variables.\nThe Apify platform uses environment variables prefixed with `ACTOR_` to pass information to Actors \nabout the execution context.\n\n| Environment variable               | Description                                                                                                                                                                                                                |\n|------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `ACTOR_ID`                         | ID of the Actor.                                                                                                                                                                                                           |\n| `ACTOR_FULL_NAME`                  | Full technical name of the Actor, in the format `owner-username/actor-name`.                                                                                                                                               |\n| `ACTOR_RUN_ID`                     | ID of the Actor run.                                                                                                                                                                                                       |\n| `ACTOR_BUILD_ID`                   | ID of the Actor build.                                                                                                                                                                                                     |\n| `ACTOR_BUILD_NUMBER`               | A string representing the version of the current Actor build.                                                                                                                                                              |\n| `ACTOR_BUILD_TAGS`                 | A comma-separated list of tags of the Actor build used in the run. Note that this environment variable is assigned at the time of start of the Actor and doesn't change over time, even if the assigned build tags change. |\n| `ACTOR_TASK_ID`                    | ID of the saved Actor task.                                                                                                                                                                                                |\n| `ACTOR_DEFAULT_KEY_VALUE_STORE_ID` | ID of the key-value store where the Actor's input and output data are stored.                                                                                                                                              |\n| `ACTOR_DEFAULT_DATASET_ID`         | ID of the dataset where you can push the data.                                                                                                                                                                             |\n| `ACTOR_DEFAULT_REQUEST_QUEUE_ID`   | ID of the request queue that stores and handles requests that you enqueue.                                                                                                                                                 |\n| `ACTOR_INPUT_KEY`                  | The key of the record in the default key-value store that holds the Actor input. Typically it's `INPUT`, but it might be something else.                                                                                   |\n| `ACTOR_MEMORY_MBYTES`              | Indicates the size of memory allocated for the Actor run, in megabytes (1,000,000 bytes). It can be used by Actors to optimize their memory usage.                                                                         |\n| `ACTOR_STARTED_AT`                 | Date when the Actor was started, in ISO 8601 format. For example, `2022-01-02T03:04:05.678`.                                                                                                                               |\n| `ACTOR_TIMEOUT_AT`                 | Date when the Actor will time out, in ISO 8601 format.                                                                                                                                                                     |\n| `ACTOR_EVENTS_WEBSOCKET_URL`       | Websocket URL where Actor may listen for events from Actor platform. See [System events](#system-events) for details.                                                                                                      |\n| `ACTOR_WEB_SERVER_PORT`            | TCP port on which the Actor can start a HTTP server to receive messages from the outside world, either as [Actor web server](#actor-web-server) or in the [Standby mode](#standby-mode).                           |\n| `ACTOR_WEB_SERVER_URL`             | A unique hard-to-guess URL under which the current Actor run's web server is accessible from the outside world. See [Actor web server](#actor-web-server) section for details.                                     |\n| `ACTOR_STANDBY_URL`                | A general public URL under which the Actor can be started and its web server accessed in the [Standby mode](#standby-mode).                                                                                                |\n| `ACTOR_MAX_PAID_DATASET_ITEMS`     | A maximum number of results that will be charged to the user using a pay-per-result Actor.                                                                                                                                 |\n| `ACTOR_MAX_TOTAL_CHARGE_USD`       | The maximum amount of money in USD an Actor can charge its user. See [Charging money](#charging-money) for details.                                                                                                        |\n\nThe Actor developer can also define custom environment variables\nthat are then passed to the Actor process both in the local development environment or on the Apify platform.\nThese variables are defined in the [Actor file](#actor-file) at `.actor/actor.json` using the `environmentVariables` directive,\nor manually in the user interface in Apify Console.\n\nThe environment variables can be set as secure in order to protect sensitive data such as API keys or passwords.\nThe value of a secure environment variable is encrypted and can only be retrieved by the Actors during their run,\nbut not outside runs. Furthermore, values of secure environment variables are omitted from the log.\n\n\u003c!-- ASTRO: \u003cCodeSwitcher\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Node.js\"\u003e --\u003e\n\n#### Node.js\n\nFor convenience, rather than using environment vars directly, we provide a `Configuration` class\nthat allows reading and updating the Actor configuration.\n\n```javascript\nconst token = Actor.config.get('token');\n\n// use different token\nActor.config.set('token', 's0m3n3wt0k3n')\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"CLI\"\u003e --\u003e\n\n#### CLI\n\n```bash\n$ echo \"$ACTOR_RUN_ID started at $ACTOR_STARTED_AT\"\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"UNIX equivalent\"\u003e --\u003e\n\n#### UNIX equivalent\n\n```bash\n$ echo $ACTOR_RUN_ID\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003c/CodeSwitcher\u003e --\u003e\n\n### Actor status\n\nEach Actor run has a status (the `status` field), which indicates its stage in the Actor's lifecycle.\nThe status can be one of the following values:\n\n\u003cdiv class=\"clear-both\" /\u003e\n\n|Status|Type| Description                                 |\n|--- |--- |---------------------------------------------|\n|`READY`|initial| Started but not allocated to any worker yet |\n|`RUNNING`|transitional| Executing on a worker                       |\n|`SUCCEEDED`|terminal| Finished successfully                       |\n|`FAILED`|terminal| Run failed                                  |\n|`TIMING-OUT`|transitional| Timing out now                              |\n|`TIMED-OUT`|terminal| Timed out                                   |\n|`ABORTING`|transitional| Being aborted by a user or system           |\n|`ABORTED`|terminal| Aborted by a user or system                 |\n\nAdditionally, the Actor run has a status message (the `statusMessage` field),\nwhich contains text for users informing them what the Actor is currently doing,\nand thus greatly improving their user experience.\n\nWhen an Actor exits, the status message is either automatically set to some default text\n(e.g. \"Actor finished with exit code 1\"), or to a custom message - see [Exit Actor](#exit-actor) for details.\n\nWhen the Actor is running, it should periodically update the status message as follows,\nto keep users informed and happy. The function can be called as often as necessary,\nthe SDK only invokes API if status changed. This is to simplify usage.\n\n\u003c!-- ASTRO: \u003cCodeSwitcher\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Node.js\"\u003e --\u003e\n\n#### Node.js\n\n```js\nawait Actor.setStatusMessage('Crawled 45 of 100 pages');\n\n// Setting status message to other Actor externally is also possible\nawait Actor.setStatusMessage('Everyone is well', { actorRunId: 123 });\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Python\"\u003e --\u003e\n\n#### Python\n\n```python\nawait Actor.set_status_message('Crawled 45 of 100 pages')\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"CLI\"\u003e --\u003e\n\n#### CLI\n\n```bash\n$ actor set-status-message \"Crawled 45 of 100 pages\"\n$ actor set-status-message --run=[RUN_ID] --token=X \"Crawled 45 of 100 pages\"\n```\n\nConvention: The end user of an Actor should never need to look into the log to understand what happened,\ne.g. why the Actor failed. All necessary information must be set by the Actor in the status message.\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003c/CodeSwitcher\u003e --\u003e\n\n### System events\n\nActors are notified by the system about various events such as a migration to another server,\n[abort operation](#abort-another-actor) triggered by another Actor, or the CPU being overloaded.\n\nCurrently, the system sends the following events:\n\n| Event name     | Payload | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |\n| -------------- | ------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `cpuInfo`      | `{ isCpuOverloaded: Boolean }` | The event is emitted approximately every second and it indicates whether the Actor is using the maximum of available CPU resources. If that’s the case, the Actor should not add more workload. For example, this event is used by the AutoscaledPool class.                                                                                                                                                                                                                                                                             |\n| `migrating`    | N/A | Emitted when the Actor running on the Apify platform is going to be migrated to another worker server soon. You can use it to persist the state of the Actor and abort the run, to speed up migration. See [Migration to another server](#migration-to-another-server).                                                                                                                                                                                                                                                                  |\n| `aborting`     | N/A | When a user aborts an Actor run on the Apify platform, they can choose to abort gracefully to allow the Actor some time before getting killed. This graceful abort emits the `aborting` event which the SDK uses to gracefully stop running crawls and you can use it to do your own cleanup as well.                                                                                                                                                                                                                                    |\n| `persistState` | `{ isMigrating: Boolean }` | Emitted in regular intervals (by default 60 seconds) to notify all components of Apify SDK that it is time to persist their state, in order to avoid repeating all work when the Actor restarts. This event is automatically emitted together with the migrating event, in which case the `isMigrating` flag is set to `true`. Otherwise the flag is `false`. Note that the `persistState` event is provided merely for user convenience, you can achieve the same effect using `setInterval()` and listening for the `migrating` event. |\n\nIn the future, the event mechanism might be extended to custom events and messages enabling communication between\nActors.\n\nUnder the hood, Actors receive system events by connecting to a web socket address specified\nby the `ACTOR_EVENTS_WEBSOCKET_URL` environment variable.\nThe system sends messages in JSON format in the following structure:\n\n```js\n{\n    // Event name\n    name: String,\n\n    // Time when the event was created, in ISO format\n    createdAt: String,\n          \n    // Optional object with payload      \n    data: Object,\n}\n```\n\nNote that some events (e.g. `persistState`) are not sent by the system via the web socket,\nbut generated virtually on the Actor SDK level.\n\n\u003c!-- ASTRO: \u003cCodeSwitcher\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Node.js\"\u003e --\u003e\n\n#### Node.js\n\n```js\n// Add event handler\nconst handler = (data) =\u003e {\n  if (data.isCpuOverloaded) console.log('Oh no, we need to slow down!');\n}\nActor.on('systemInfo', handler);\n\n// Remove all handlers for a specific event\nActor.off('systemInfo');\n\n// Remove a specific event handler\nActor.off('systemInfo', handler);\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Python\"\u003e --\u003e\n\n#### Python\n\n```python\nfrom apify import Actor, Event\n\n# Add event handler\nasync def handler(data):\n  if data.cpu_info.is_overloaded:\n    print('Oh no, we need to slow down!')\n\nActor.on(Event.SYSTEM_INFO, handler);\n\n# Remove all handlers for a specific event\nActor.off(Event.SYSTEM_INFO);\n\n# Remove a specific event handler\nActor.off(Event.SYSTEM_INFO, handler);\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"UNIX equivalent\"\u003e --\u003e\n\n#### UNIX equivalent\n\n```c\nsignal(SIGINT, handle_sigint);\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003c/CodeSwitcher\u003e --\u003e\n\n### Get memory information\n\nGet information about the total and available memory of the Actor’s container or local system.\nThis is useful to, for example, auto-scale a pool\nof workers used for crawling large websites.\n\n\u003c!-- ASTRO: \u003cCodeSwitcher\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Node.js\"\u003e --\u003e\n\n#### Node.js\n\n```js\nconst memoryInfo = await Actor.getMemoryInfo();\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"UNIX equivalent\"\u003e --\u003e\n\n#### UNIX equivalent\n\n```bash\n# Print memory usage of programs\n$ ps -a\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003c/CodeSwitcher\u003e --\u003e\n\n### Start another Actor\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"Actor can start other Actors, if they have permission. It can override the default dataset or key-value store, and e.g. forwarding the data to another named dataset, that will be consumed by the other Actor.\"\n    position=\"content\"\n    image={illuAPIStartAnother}\n    noCaption\n/\u003e\n--\u003e\n\nActor can start other Actors, if they have permission.\n\nThe Actor can override the default dataset or key-value store,\nand, e.g. forward the data to another named dataset that will be consumed by the other Actor.\n\nThe `call` operation waits for the other Actor to finish, the `start` operation\nreturns immediately.\n\n\u003c!-- ASTRO: \u003cCodeSwitcher\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Node.js\"\u003e --\u003e\n\n#### Node.js\n\n```js\n// Start Actor and return a Run object\nconst run = await Actor.start(\n    'apify/google-search-scraper', // name of the Actor to start\n    { queries: 'test' }, // input of the Actor\n    { memory: 2048 }, // run configuration\n);\n\n// Start Actor and wait for it to finish\nconst run2 = await Actor.call(\n  'apify/google-search-scraper', \n  { queries: 'test' },\n  { memory: 2048 },\n);\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"CLI\"\u003e --\u003e\n\n#### CLI\n\n```bash\n# On stdout, the commands emit Actor run object (in text or JSON format),\n# we shouldn't wait for finish, for that it should be e.g. \"execute\"\n$ apify call apify/google-search-scraper queries='test\\ntest2' \\\n  countryCode='US'\n$ apify call --json apify/google-search-scraper '{ \"queries\": }'\n$ apify call --input=@data.json --json apify/google-search-scraper\n$ apify call --memory=1024 --build=beta apify/google-search-scraper\n$ apify call --output-record-key=SCREENSHOT apify/google-search-scraper\n\n# Pass input from stdin\n$ cat input.json | actor call apify/google-search-scraper --json\n\n# Call local actor during development\n$ apify call file:../some-dir someInput='xxx'\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Slack\"\u003e --\u003e\n\n#### Slack\n\nIt will also be possible to run Actors from the Slack app.\nThe following command starts the Actor, and then prints the messages to a Slack channel.\n\n```\n/apify start bob/google-search-scraper startUrl=afff\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"API\"\u003e --\u003e\n\n#### API\n\n```\n[POST] https://api.apify.com/v2/actors/apify~google-search-scraper/run\n\n[POST|GET] https://api.apify.com/v2/actors/apify~google-search-scraper/run-sync?\n  token=rWLaYmvZeK55uatRrZib4xbZs\u0026\n  outputRecordKey=OUTPUT\n  returnDataset=true\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"UNIX equivalent\"\u003e --\u003e\n\n#### UNIX equivalent\n\n```bash\n# Run a program in the background\n$ command \u003carg1\u003e, \u003carg2\u003e, … \u0026\n```\n\n```c\n// Spawn another process\nposix_spawn();\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003c/CodeSwitcher\u003e --\u003e\n\n### Metamorph\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"Metamorph is the most magical Actor operation. It replaces running Actor’s Docker image with another Actor, similarly to UNIX `exec` command. It is used for building new Actors on top of existing ones. You simply define input schema and write README for a specific use case, and then delegate the work to another Actor.\"\n    position=\"content\"\n    image={illuAPIMetamorph}\n    noCaption\n/\u003e\n--\u003e\n\nThis is the most magical Actor operation. It replaces a running Actor’s Docker image with another Actor,\nsimilarly to UNIX `exec` command.\nIt is used for building new Actors on top of existing ones.\nYou simply define the input schema and write README for a specific use case,\nand then delegate the work to another Actor.\n\nThe target Actor inherits the default storages used by the calling Actor.\nThe target Actor input is stored to the default key-value store,\nunder a key such as `INPUT-2` (the actual key is passed via the `ACTOR_INPUT_KEY` [environment variable](#environment-variables)).\nInternally, the target Actor can recursively metamorph into another Actor.\n\nAn Actor can metamorph only to Actors that have compatible output schema as the main Actor,\nin order to ensure logical and consistent outcomes for users.\nIf the output schema of the target Actor is not compatible, the system should throw an error.\n\n\u003c!-- ASTRO: \u003cCodeSwitcher\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Node.js\"\u003e --\u003e\n\n#### Node.js\n\n```js\nawait Actor.metamorph(\n    'bob/web-scraper',\n    { startUrls: [ \"https://www.example.com\" ] },\n    { memoryMbytes: 4096 },\n);\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"CLI\"\u003e --\u003e\n\n#### CLI\n\n```bash\n$ actor metamorph bob/web-scraper startUrls=http://example.com\n$ actor metamorph --input=@input.json --json --memory=4096 \\\n  bob/web-scraper\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"UNIX equivalent\"\u003e --\u003e\n\n#### UNIX equivalent\n\n```bash\n$ exec /bin/bash\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003c/CodeSwitcher\u003e --\u003e\n\n### Attach webhook to an Actor run\n\nRun another Actor or an external HTTP API endpoint after an Actor run finishes or fails.\n\n\u003cdiv class=\"clear-both\" /\u003e\n\n\u003c!-- ASTRO: \u003cCodeSwitcher\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Node.js\"\u003e --\u003e\n\n#### Node.js\n\n```js\nawait Actor.addWebhook({\n    eventType: ['ACTOR.RUN.SUCCEEDED', 'ACTOR.RUN.FAILED'],\n    requestUrl: 'http://api.example.com?something=123',\n    payloadTemplate: `{\n        \"userId\": {{userId}},\n        \"createdAt\": {{createdAt}},\n        \"eventType\": {{eventType}},\n        \"eventData\": {{eventData}},\n        \"resource\": {{resource}}\n    }`,\n});\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"CLI\"\u003e --\u003e\n\n#### CLI\n\n```bash\n$ actor add-webhook \\\\\n  --event-types=ACTOR.RUN.SUCCEEDED,ACTOR.RUN.FAILED \\\\\n  --request-url=https://api.example.com \\\\\n  --payload-template='{ \"test\": 123\" }'\n\n$ actor add-webhook --event-types=ACTOR.RUN.SUCCEEDED \\\\\n  --request-actor=apify/send-mail \\\\\n  --memory=4096 --build=beta \\\\\n  --payload-template=@template.json\n\n# Or maybe have a simpler API for self-actor?\n$ actor add-webhook --event-types=ACTOR.RUN.SUCCEEDED --request-actor=apify/send-mail \n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"UNIX equivalent\"\u003e --\u003e\n\n#### UNIX equivalent\n\n```bash\n# Execute commands sequentially, based on their status\n$ command1; command2    # (command separator)\n$ command1 \u0026\u0026 command2  # (\"andf\" symbol)\n$ command1 || command2  # (\"orf\" symbol)\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003c/CodeSwitcher\u003e --\u003e\n\n### Abort another Actor\n\nAbort itself or another Actor running on the Apify platform.\nAborting an Actor changes its [status](#actor-status) to `ABORTED`.\n\n\u003cdiv class=\"clear-both\" /\u003e\n\n\u003c!-- ASTRO: \u003cCodeSwitcher\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Node.js\"\u003e --\u003e\n\n#### Node.js\n\n```js\nawait Actor.abort({ statusMessage: 'Your job is done, friend.', actorRunId: 'RUN_ID' });\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"CLI\"\u003e --\u003e\n\n#### CLI\n\n```bash\n$ actor abort --run-id RUN_ID \n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"UNIX equivalent\"\u003e --\u003e\n\n#### UNIX equivalent\n\n```bash\n# Terminate a program\n$ kill \u003cPID\u003e\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003c/CodeSwitcher\u003e --\u003e\n\n### Reboot an Actor\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"Sometimes, an Actor might get into some error state from which it's not safe or possible to recover, e.g. an assertion error or a web browser crash. Rather than crashing and potentially failing the user job, the Actor can reboot its own Docker container and continue work from its previously persisted state.\"\n    position=\"right\"\n    image={illuAPIReboot}\n    noCaption\n/\u003e\n--\u003e\n\nSometimes, an Actor might get into some error state from which it's not safe or possible to recover,\ne.g. an assertion error or a web browser crash. Rather than crashing and potentially failing the user job,\nthe Actor can reboot its own Docker container and continue work from its previously persisted state.\n\nNormally, if an Actor crashes, the system also restarts its container, but\nif that happens too often in a short period of time, the system\nmight completely [abort](#actor-status) the Actor run.\nThe reboot operation can be used by the Actor developer to indicate that\nthis is a controlled operation, and not to be considered by the system as a crash.\n\n\u003cdiv class=\"clear-both\" /\u003e\n\n\u003c!-- ASTRO: \u003cCodeSwitcher\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Node.js\"\u003e --\u003e\n\n#### Node.js\n\n```js\nawait Actor.reboot();\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Python\"\u003e --\u003e\n\n#### Python\n\n```python\nawait Actor.reboot()\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"CLI\"\u003e --\u003e\n\n#### CLI\n\n```bash\n$ actor reboot \n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003c/CodeSwitcher\u003e --\u003e\n\n### Actor web server\n\nAn Actor can launch an HTTP web server that is exposed to the outside world to handle requests.\nThis enables Actors to provide a custom HTTP API to integrate with other systems,\nto provide a web application for human users, to show Actor run details, diagnostics, charts,\nor to run an arbitrary web app.\n\nThe port on which the Actor can launch the web server\nis specified by the `ACTOR_WEB_SERVER_PORT` environment variable.\n\nOnce the web server is started, it is exposed to the public internet on a **live view URL** identified\nby the `ACTOR_WEB_SERVER_URL`, for example:\n\n```\nhttps://hard-to-guess-identifier.runs.apify.net\n```\n\nThe live view URL has a unique hostname, which is practically impossible to guess.\nThis lets you keep the web server hidden from the public yet accessible from the external internet by any parties\nwith whom you share the URL.\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"An Actor can launch an HTTP web server that is exposed to the outside world to handle requests. This enables Actors to provide a custom HTTP API to integrate with other systems, to provide a web application for human users, to show Actor run details, diagnostics, charts, or to run an arbitrary web app.\"\n    position=\"left\"\n    image={illuAPIWebServer}\n    noCaption\n/\u003e\n--\u003e\n\n\u003cdiv class=\"clear-both\" /\u003e\n\n\u003c!-- ASTRO: \u003cCodeSwitcher\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Node.js\"\u003e --\u003e\n\n#### Node.js\n\n```js\nconst express = require('express');\nconst app = express();\n\napp.get('/', (req, res) =\u003e {\n  res.send('Hello World!')\n})\n\napp.listen(process.env.ACTOR_WEB_SERVER_PORT, () =\u003e {\n  console.log(`Example live view web server running at ${process.env.ACTOR_WEB_SERVER_URL}`)\n})\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003c/CodeSwitcher\u003e --\u003e\n\n### Standby mode\n\nActor Standby mode lets Actors run in the background and respond to incoming HTTP requests,\nlike a web or API server.\n\nStarting an Actor run requires launching a Docker container, and so it comes with a performance penalty, sometimes many seconds for large images.\nFor batch jobs this penalty is negligible, but for quick request-response interactions it becomes inefficient.\nStandby mode lets developers run Actors as web servers to run jobs that require quick response times.\n\nTo use Standby mode, start an HTTP web server at the `ACTOR_WEB_SERVER_PORT` TCP port,\nand process HTTP requests.\n\nThe Actor system publishes a Standby Actor's web server\nat a URL reported in the `ACTOR_STANDBY_URL` environment variable,\nand will automatically start or abort an Actor run as needed by the volume of HTTP requests or system load.\nThe external Standby public URL might look like this:\n\n```\nhttps://bob--screenshotter.apify.actor\n```\n\nUnlike the live view URL reported in the `ACTOR_WEB_SERVER_URL` environment variable,\nthe Standby URL is the same for all runs of the Actor, and it's intended to be publicly known.\nThe Actor system can perform authentication of the requests going to the Standby URL using API tokens.\n\nCurrently, the specific Standby mode settings, authentication options, or OpenAPI schema are not part of this Actor specification,\nbut they might be in the future introduced as new settings in the `actor.json` file.\n\n### Migration to another server\n\nActors can be migrated from another host server from time to time, especially long-running ones.\nWhen migration is imminent, the system sends the Actor the `migrating` [system event](#system-events)\nto inform the Actor, so that it can persist its state to storages.\nAll executed writes to the default Actor [storage](#storage) are guaranteed to be persisted before the migration.\nAfter migration, the Actor is restarted on a new host. It can restore its customer state from the storages again.\n\n### Charging money\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"To run an Actor on the Apify platform or another cloud platform, a user typically needs to pay to cover the computing costs. Additionally, the platforms are free to introduce other monetization mechanisms, such as charging the users a fixed monthly fee for 'renting' the Actor, or a variable fee for the number of results produced by the Actor. These charging mechanisms are beyond the scope of this whitepaper.\"\n    position=\"right\"\n    image={illuSharingChargingMoney}\n    noCaption\n/\u003e\n--\u003e\n\nTo run an Actor on the Apify platform or another cloud platform,\na user typically needs to pay to cover the computing costs.\nAdditionally, the platforms are free to introduce other [monetization](#monetization)\nmechanisms, such as charging the users a fixed monthly fee for \"renting\" the Actor,\nor a variable fee for the number of results produced by the Actor.\nThese charging mechanisms are beyond the scope of this whitepaper.\n\nOn top of these external monetization systems, Actors provide\na built-in monetization system that enables developers to charge users variable\namounts per event, e.g. based on the number of returned results,\ncomplexity of the input, or the cost of external APIs used internally by the Actor.\n\nAn Actor can dynamically charge the current user a specific amount of money\nby calling the `charge` function.\nUsers of Actors can limit the maximum amount to be charged by the Actor\nusing the `maxTotalChargeUsd` run option, which is then passed to the Actor using\nthe `ACTOR_MAX_TOTAL_CHARGE_USD` environment variable.\nThe Actor can call the `charge` function as many times as necessary,\nbut once the total sum of charged credits would exceed this maximum limit,\nthe invocation of the function throws an error.\n\nWhen a paid Actor subsequently starts another paid Actor, the charges performed\nby the subsequent Actors are taken from the calling Actor's allowance.\nThis enables Actor economy, where Actors hierarchically pay other Actors or external APIs\nto perform parts of the job.\n\nAn Actor developer can also charge the current user of an Actor a specific amount of USD.\n\n\u003c!-- ASTRO: \u003cCodeSwitcher\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Node.js\"\u003e --\u003e\n\n#### Node.js\n\n```js\nconst chargeInfo = await Actor.charge({\n  eventName: 'gpt-4o-token',\n  count: 1000,\n  chargePerEventUsd: 0.0001,\n});\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Python\"\u003e --\u003e\n\n#### Python\n```python\ncharge_info = await Actor.charge(\n  event_name='gpt-4o-token',\n  count=1000,\n  charge_per_event_usd=0.0001\n)\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"CLI\"\u003e --\u003e\n\n#### CLI\n```bash\n$ actor charge gpt-4o-token \\\n  --count=1000\n  --chargePerEventUsd=0.0001\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003c/CodeSwitcher\u003e --\u003e\n\nAn Actor user can specify the maximum amount they are willing to pay when starting an Actor.\n\n\u003c!-- ASTRO: \u003cCodeSwitcher\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Node.js\"\u003e --\u003e\n\n#### Node.js\n\n```js\nconst run = await Actor.call(\n  'bob/analyse-images',\n  { imageUrls: ['https://www.example.com/image.png'] },\n  {\n      // By default this is 0, hence Actors cannot charge users unless they explicitly allow that.\n      maxTotalChargeUsd: 5,\n  },\n);\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"Python\"\u003e --\u003e\n\n#### Python\n\n```python\nrun = await Actor.call(\n    'bob/analyse-images' ,\n    {'imageUrls': ['https://www.example.com/image.png']},\n    max_total_charge_usd=5\n)\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003cCodeExample title=\"CLI\"\u003e --\u003e\n\n#### CLI\n```bash\n$ actor call bob/analyse-images \\\n  --input='{\"imageUrls\": [\"https://www.example.com/image.png\"]}'\n  --max-total-charge-usd=5\n```\n\n\u003c!-- ASTRO: \u003c/CodeExample\u003e --\u003e\n\u003c!-- ASTRO: \u003c/CodeSwitcher\u003e --\u003e\n\n#### Rules for building Actors with variable charging\n\nIf your Actor is charging users, you need to make sure at the earliest time possible\nthat the Actor is being run with sufficient credits with respect to its input.\nIf the maximum credits specified by the `ACTOR_MAX_TOTAL_CHARGE_USD` environment variable is\nnot sufficient for the Actor's operation with respect\nto the input (e.g. user is requesting too many results for too little money),\nthe Actor must fail immediately with an explanatory error status message for the user,\nand not charge the user anything.\n\nYou must also charge users only **after** you have incurred the costs,\nnot before. If an Actor fails in the middle of a run or is aborted, the users\nonly need to be charged for results they actually received.\nNothing will make users of your Actors angrier than charging them for something they didn't receive.\n\n## Actor definition files\n\nThe Actor system uses several special files that define Actor metadata, documentation,\ninstructions how to build and run it, input and output schema, etc.\n\n**These files MUST be stored in the `.actor` directory placed in Actor's top-level directory.\nThe entire `.actor` directory should be added to the source control.**\nThe only required files are [Actor file](#actor-file) and [Dockerfile](#dockerfile),\nall other files are optional.\n\nThe Actor definition files are used by the CLI (e.g. by `apify push` and `apify run` commands),\nas well as when building Actors on the Apify platform.\nThe motivation to place the files into a separate directory\nis to keep the source code repository tidy and to prevent interactions with other source files,\nin particular when creating an Actor from pre-existing software repositories.\n\n### Actor file\n\nThis is the main definition file of the Actor,\nand it must always be present at `.actor/actor.json`.\nThis file is in JSON format and contains a single object, whose properties\ndefine the main features of the Actor and link to all other necessary files.\n\nFor details, see the [Actor file specification](./pages/ACTOR_FILE.md) page.\n\n#### Example Actor file at `.actor/actor.json`\n\n```json\n{\n  \"actorSpecification\": 1,\n  \"name\": \"screenshotter\",\n  \"title\": \"Screenshotter\",\n  \"description\": \"Take a screenshot of any URL\",\n  \"version\": \"0.0\",\n  \"inputSchema\": \"./input_schema.json\",\n  \"outputSchema\": \"./output_schema.json\",\n  \"dockerfile\": \"./Dockerfile\"\n}\n```\n\n### Dockerfile\n\nThis file contains instructions for the system on how to build the Actor's\nDocker image and how to run it.\nActors are started by running their Docker image,\nboth locally using the `apify run` command\nas well as on the Apify platform.\n\nThe Dockerfile is referenced from the [Actor file](#actor-file) using the `dockerfile`\ndirective, and is typically stored at `.actor/Dockerfile`.\n\nNote that paths in Dockerfile are always specified relative to the Dockerfile's location.\nLearn more about Dockerfiles in the official [Docker reference](https://docs.docker.com/engine/reference/builder/).\n\n#### Example Dockerfile of an Actor\n\n```dockerfile\n# Specify the base Docker image. You can read more about\n# the available images at https://crawlee.dev/docs/guides/docker-images\n# You can also use any other image from Docker Hub.\nFROM apify/actor-node-playwright-chrome:22-1.46.0 AS builder\n\n# Copy just package.json and package-lock.json\n# to speed up the build using Docker layer cache.\nCOPY --chown=myuser package*.json ./\n\n# Install all dependencies. Don't audit to speed up the installation.\nRUN npm install --include=dev --audit=false\n\n# Next, copy the source files using the user set\n# in the base image.\nCOPY --chown=myuser . ./\n\n# Install all dependencies and build the project.\n# Don't audit to speed up the installation.\nRUN npm run build\n\n# Create final image\nFROM apify/actor-node-playwright-firefox:22-1.46.0\n\n# Copy just package.json and package-lock.json\n# to speed up the build using Docker layer cache.\nCOPY --chown=myuser package*.json ./\n\n# Install NPM packages, skip optional and development dependencies to\n# keep the image small. Avoid logging too much and print the dependency\n# tree for debugging\nRUN npm --quiet set progress=false \\\n    \u0026\u0026 npm install --omit=dev --omit=optional \\\n    \u0026\u0026 echo \"Installed NPM packages:\" \\\n    \u0026\u0026 (npm list --omit=dev --all || true) \\\n    \u0026\u0026 echo \"Node.js version:\" \\\n    \u0026\u0026 node --version \\\n    \u0026\u0026 echo \"NPM version:\" \\\n    \u0026\u0026 npm --version \\\n    \u0026\u0026 rm -r ~/.npm\n\n# Install all required Playwright dependencies for Firefox\nRUN npx playwright install firefox\n\n# Copy built JS files from builder image\nCOPY --from=builder --chown=myuser /home/myuser/dist ./dist\n\n# Next, copy the remaining files and directories with the source code.\n# Since we do this after NPM install, quick build will be really fast\n# for most source file changes.\nCOPY --chown=myuser . ./\n\n# Run the image. If you know you won't need headful browsers,\n# you can remove the XVFB start script for a micro perf gain.\nCMD ./start_xvfb_and_run_cmd.sh \u0026\u0026 ./run_protected.sh npm run start:prod --silent\n```\n\n### README\n\nThe README file contains Actor documentation written\nin [Markdown](https://docs.github.com/en/github/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax).\nIt should contain a great explanation of what the Actor does and how to use it.\nThe README file is used to generate an Actor's public web page on Apify and for other purposes.\n\nThe README file is referenced from the [Actor file](#actor-file) using the `readme`\nproperty, and typically stored at `.actor/README.md`.\n\nGood documentation makes good Actors.\n[Read the Apify Actor marketing playbook](https://apify.notion.site/3fdc9fd4c8164649a2024c9ca7a2d0da?v=6d262c0b026d49bfa45771cd71f8c9ab) for tips on how to write great READMEs and market Actors.\n\n### Input schema file\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"Actors accept an input JSON object on start, whose schema can be defined by the input schema file. This file is referenced in the Actor file as the `input` property. It is a standard JSON Schema file with our extensions, and it is typically stored at .actor/input_schema.json.\"\n    position=\"right\"\n    image={illuDefinitionFilesInputSchemaFile}\n    noCaption\n/\u003e\n--\u003e\n\nActors accept an [input](#input) JSON object on start, whose schema can be defined\nby the input schema file. This file is referenced in the Actor file (`.actor/actor.json`) file\nas the `input` property.\nIt is a standard JSON Schema file with our extensions, and it is typically stored at `.actor/input_schema.json`.\n\nThe input schema file defines properties accepted by Actor on input. It is used by the system to:\n\n- Validate the passed input JSON object on Actor run,\n  so that Actors don't need to perform input validation and error handling in their code.\n- Render user interface for Actors to make it easy for users to run and test them manually.\n- Generate Actor API documentation and integration code examples on the web or in CLI,\n  making Actors easy to integrate for users.\n- Simplify integration of Actors into automation workflows such as Zapier or Make, by providing smart connectors\n  that smartly pre-populate and link Actor input properties.\n\nFor details, see [Actor input schema file specification](./pages/INPUT_SCHEMA.md).\n\n\u003cdiv class=\"clear-both\" /\u003e\n\nThis is an example of the input schema file for the `bob/screenshotter` Actor:\n\n```json\n{\n  \"actorInputSchemaVersion\": 1,\n  \"title\": \"Input schema for Screenshotter Actor\",\n  \"description\": \"Enter a web page URL and it will take its screenshot with a specific width\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"url\": {\n      \"title\": \"URL\",\n      \"type\": \"string\",\n      \"editor\": \"textfield\",\n      \"description\": \"URL of the webpage\"\n    },\n    \"width\": {\n      \"title\": \"Viewport width\",\n      \"type\": \"integer\",\n      \"description\": \"Width of the browser window.\",\n      \"default\": 1200,\n      \"minimum\": 1,\n      \"unit\": \"pixels\"\n    }\n  },\n  \"required\": [\n    \"url\"\n  ]\n}\n```\n\n### Output schema file\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"Similarly to input, Actors can generate an output JSON object, which links to their results. The Actor output schema file defines how such output object looks like, including types of its properties and description. This file is referenced in the Actor file as the `output` property. It is a standard JSON Schema file with our extensions, and it is typically stored at .actor/output_schema.json.\"\n    position=\"right\"\n    image={illuDefinitionFilesOutputSchemaFile}\n    noCaption\n/\u003e\n--\u003e\n\nSimilarly to input, Actors can generate an [output](#output) JSON object, which links to their results.\nThe Actor output schema file defines how such output object looks like,\nincluding types of its properties and description.\nThis file is referenced in the Actor file (`.actor/actor.json`) file\nas the `output` property.\nIt is a standard JSON Schema file with our extensions, and it is typically stored at `.actor/output_schema.json`.\n\nThe output schema describes how the Actor stores its results, and it is used by the other systems:\n\n- Generate API documentation for users of Actors to figure where to find results.\n- Publish OpenAPI specification to make it easy for callers of Actors to figure where to find results.\n- Enable integrating Actors with external systems and automated workflows.\n\nFor details, see [Actor output schema file specification](./pages/OUTPUT_SCHEMA.md).\n\n\u003cdiv class=\"clear-both\" /\u003e\n\nThis is an example of the output schema file for the `bob/screenshotter` Actor:\n\n```json\n{\n  \"actorOutputSchemaVersion\": 1,\n  \"title\": \"Output schema for Screenshotter Actor\",\n  \"description\": \"The URL to the resulting screenshot\",\n  \"properties\": {\n    \"screenshotUrl\": {\n      \"type\": \"string\",\n      \"title\": \"Web page screenshot\",\n      \"resourceType\": \"file\",\n      \"template\": \"{{actorRun.defaultKeyValueStoreUrl}}/screenshot.png\"\n    }\n  }\n}\n```\n\n### Storage schema files\n\nBoth main Actor file and input and output schema files can additionally reference schema files\nfor specific storages.\nThese files have custom JSON-based formats, see:\n\n- [Dataset schema file](./pages/DATASET_SCHEMA.md)\n- [Key-value store schema file](./pages/KEY_VALUE_STORE_SCHEMA.md)\n- [Request queue schema file](./pages/REQUEST_QUEUE_SCHEMA.md)\n\nThese storage schemas are used to ensure that stored objects or files\nfulfil specific criteria, their fields have certain types, etc.\nOn the Apify platform, the schemas can be applied to the storages directly,\nwithout Actors.\n\nNote that all the storage schemas are weak, in a sense that if the schema doesn't define a property,\nsuch property can be added to the storage and have an arbitrary type.\nOnly properties explicitly mentioned by the schema\nare validated. This is an important feature which allows extensibility.\nFor example, a data deduplication Actor might require on input datasets\nthat have an `uuid: String` field in objects, but it does not care about other fields.\n\n### Backward compatibility\n\nIf the `.actor/actor.json` file is missing,\nthe system falls back to the legacy mode,\nand looks for `apify.json`, `Dockerfile`, `README.md` and `INPUT_SCHEMA.json`\nfiles in the Actor's top-level directory instead.\nThis behavior might be deprecated in the future.\n\n## Development\n\nActors can be developed locally, using a git integration, or in a web IDE.\nThe SDK is currently available for Node.js, Python, and CLI.\n\n### Local development\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"The Actor programming model is language agnostic, but the framework has native support for detection of the JavaScript and Python languages.\"\n    position=\"right\"\n    image={illuDevelopmentLocal}\n    noCaption\n/\u003e\n--\u003e\n\nThe Actor programming model is language agnostic, but the framework has native support for detection of the JavaScript and Python languages. \n\nTip: [Apify CLI](https://docs.apify.com/cli/docs/next/reference#apify-create-actorname) provides [convenient templates](https://apify.com/templates) to bootstrap an Actor in Python, JavaScript, and TypeScript.\n\nThis example is describing how to create a simple \"echo\" Actor locally. The Actor will retrieve the [Input Object](#input) and it will [push](#push-results-to-dataset) it to the default [dataset](#dataset). \n\n#### Bootstrap the Actor directory\nThe `actor bootstrap` CLI command will automatically generate the `.actor` directory and configuration files:\n\n```bash\n$ actor bootstrap\n? Actor name: actor-test\nSuccess: The Actor has been initialized in the current directory.\n$ tree -a\n.\n|-- .actor\n|   `-- actor.json\n|-- .gitignore\n`-- storage\n    |-- datasets\n    |   `-- default\n    |-- key_value_stores\n    |   `-- default\n    |       `-- INPUT.json\n    `-- request_queues\n        `-- default\n```\n\nThe command works on the best-effort basis,\ncreating necessary configuration files for the specific programming language and libraries.\n\nNote: this command is not yet available and represents a future vision for the CLI.\n\n#### Add the Actor code\n```\n$ cat \u003c\u003c EOF \u003e Dockerfile\nFROM node:alpine\nRUN npm -g install apify-cli \nCMD actor push-data $(actor get-input)\nEOF\n```\n\n#### Run to test the Actor locally\n```\n$ echo '{\"bar\": \"foo\"}' | actor run -o -s\n[{\n  \"foo\": \"bar\"\n}]\n```\n`apify run` - starts the Actor using Dockerfile\nreferenced from `.actor/actor.json` or Dockerfile in the Actor top-level directory\n(if the first is not present)\n\n### Deployment to Apify platform\n\nThe `apify push` CLI command takes information from the `.actor` directory and builds an Actor on the Apify platform,\nso that you can run it remotely.\n\n```bash\n$ apify login\n? Choose how you want to log in to Apify (Use arrow keys)\n❯ Through Apify Console in your default browser\n$ apify push\n```\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"The `apify push` CLI command takes information from the `.actor` directory and builds an Actor on the Apify platform, so that you can run it remotely.\"\n    position=\"left\"\n    image={illuDevelopmentDeployment}\n    noCaption\n/\u003e\n--\u003e\n\n### Continuous integration and delivery\n\nThe source code of Actors can be hosted on external source control systems like GitHub or GitLab,\nand integrated into CI/CD pipelines.\nThe implementation details, as well as details of the Actor build and version management process,\nare beyond the scope of this whitepaper.\n\n### Actorizing existing code\n\nYou can repackage many existing software repositories\nas an Actor by creating the `.actor/` directory with the [Actor definition files](#actor-definition-files),\nand providing a Dockerfile with instruction how to run the software.\n\nThe `actor` CLI command can be used from the Dockerfile's `RUN` script transform the Actor JSON input\ninto the configuration of the software, usually passed via command-line arguments,\nand then store the Actor output results. \n\nThis example wraps the [`curl`](https://curl.se/docs/tutorial.html) UNIX command and pushes the result to the Actor's [key-value store](#key-value-store):\n\n```bash\nFROM alpine/curl:latest\n\n# Install node to the Alpine Docker image\nCOPY --from=node:current-alpine /usr/lib /usr/lib\nCOPY --from=node:current-alpine /usr/local/lib /usr/local/lib\nCOPY --from=node:current-alpine /usr/local/include /usr/local/include\nCOPY --from=node:current-alpine /usr/local/bin /usr/local/bin\n\n# Install the Actor CLI\nRUN npm -g install apify-cli\n\nCMD curl $(actor get-input) | actor set-value example-com --contentType text/html\n```\n\nActorization of existing code gives developers an easy way to give their code\na presence in the cloud in the form of an Actor, so that the users can easily try it without\nhaving to install and manage it locally.\n\n## Sharing and publishing\n\nOnce an Actor is developed, the Actor platform lets you share it with other specific users,\nand decide whether you want to make its source code open or closed.\n\nYou can also publish the Actor for anyone to use on a marketplace like [Apify Store](https://apify.com/store).\nThe Actor will get a public landing page like `https://apify.com/bob/screenshotter`,\nshowing its README, description of inputs, outputs, API examples, etc.\nOnce published, your Actor is automatically exposed to organic traffic of users and potential customers.\n\n![Apify Actor Store](./img/apify-store.png)\n\n\u003c!-- ASTRO: \u003cPicture src={illuApifyStore} alt=\"Apify Store\" formats={['avif', 'webp']} /\u003e --\u003e\n\n### Monetization\n\n\u003c!-- ASTRO:\n\u003cIllustration\n    description=\"The monetization options for Actors include fixed rental fee, payment per result, or payment per event.\"\n    position=\"right\"\n    image={illuSharingMonetization}\n    noCaption\n/\u003e\n--\u003e\n\nTo build a SaaS product, you usually need to:\n\n1. Develop the product\n2. Write documentation\n3. Find and buy a domain name\n4. Set up a website\n5. Setup cloud infrastructure where it runs and scales\n6. Handle payments, billing, and taxes\n7. Marketing (content, ads, SEO, and more)\n8. Sales (demos, procurement)\n\nBuilding software as an Actor and deploying it to the Apify platform changes this to:\n\n1. Develop the Actor\n2. Write the README\n3. Publish the Actor on Apify Store\n\nPackaging your software as Actors makes it faster to launch new small SaaS products and then earn income on them,\nusing various monetization options, e.g. fixed rental fee, payment per result,\nor payment per event (see [Charging money](#charging-money)).\nThis monetization gives developers an incentive to further develop and maintain their Actors.\n\nActors provide a new way for software developers like you to monetize their skills,\nbringing the creator economy model to SaaS.\n\nFor more details, read our essay [Make passive income developing web automation Actors](https://blog.apify.com/make-regular-passive-income-developing-web-automation-Actors-b0392278d085/).\n\n## Future work\n\nThe goal of this whitepaper is to introduce the Actor philosophy and programming model to other developers,\nto receive feedback, and to open the way to making Actors an open standard.\nTo create an open standard, we need to:\n\n- Define a standardized low-level HTTP REST API interface for the Actor system,\n  to separate \"frontend\" and \"backend\" Actor programming model implementations.\n  For example, if somebody wants to build support for the Actor programming model in Rust,\n  they should just need to write a Rust \"frontend\" translating the commands to HTTP API calls,\n  rather than having to implement the entire system. And equally, if one decides\n  to develop a new Actor \"backend\", all existing client libraries for Rust or other languages should work with it.\n- Finalize specification of all the schema files, including [output](#output-schema-file) and [storage](#storage-schema-files) schema files.\n- Clearly separate what is the part of the standard and what is up to the discretion of the implementations.\n\n\n## Links\n\n- [Apify Store](https://apify.com/store)\n- [Monetize your Actor on Apify](https://apify.com/partners/actor-developers)\n- [Open-source Actors on GitHub](https://github.com/search?q=path%3A.actor%2Factor.json+\u0026type=code)\n","funding_links":[],"categories":["🌐 Web Development - Frontend"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapify%2Factor-whitepaper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapify%2Factor-whitepaper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapify%2Factor-whitepaper/lists"}