From 7ca6d5970ec75b133697c7b7705de555f3167ffa Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Thu, 4 Jun 2026 16:47:22 +0200 Subject: [PATCH 01/10] docs: Fix inaccuracies, unify wording, and expand SDK documentation --- docs/01_introduction/index.mdx | 13 +++- docs/01_introduction/quick-start.mdx | 9 ++- docs/02_concepts/01_actor_lifecycle.mdx | 2 +- docs/02_concepts/02_actor_input.mdx | 6 +- docs/02_concepts/03_storages.mdx | 16 +++-- docs/02_concepts/04_actor_events.mdx | 32 +++++---- docs/02_concepts/05_proxy_management.mdx | 12 +++- .../06_interacting_with_other_actors.mdx | 4 ++ docs/02_concepts/07_webhooks.mdx | 4 ++ docs/02_concepts/08_access_apify_api.mdx | 14 +++- docs/02_concepts/09_logging.mdx | 12 +++- docs/02_concepts/10_configuration.mdx | 25 ++++++- docs/02_concepts/11_pay_per_event.mdx | 12 ++-- docs/02_concepts/12_storage_clients.mdx | 72 +++++++++++++++++++ docs/02_concepts/code/04_actor_events.py | 9 +-- .../code/12_custom_storage_client.py | 23 ++++++ .../code/12_shared_request_queue.py | 23 ++++++ docs/04_upgrading/upgrading_to_v2.md | 6 +- docs/04_upgrading/upgrading_to_v3.md | 8 ++- docs/04_upgrading/upgrading_to_v4.md | 2 +- src/apify/storage_clients/__init__.py | 3 +- website/docusaurus.config.js | 4 -- 22 files changed, 253 insertions(+), 58 deletions(-) create mode 100644 docs/02_concepts/12_storage_clients.mdx create mode 100644 docs/02_concepts/code/12_custom_storage_client.py create mode 100644 docs/02_concepts/code/12_shared_request_queue.py diff --git a/docs/01_introduction/index.mdx b/docs/01_introduction/index.mdx index 2e8039799..a46df46e0 100644 --- a/docs/01_introduction/index.mdx +++ b/docs/01_introduction/index.mdx @@ -9,7 +9,16 @@ import CodeBlock from '@theme/CodeBlock'; import IntroductionExample from '!!raw-loader!./code/01_introduction.py'; -The Apify SDK for Python is the official library for creating [Apify Actors](https://docs.apify.com/platform/actors) in Python. It provides useful features like Actor lifecycle management, local storage emulation, and Actor event handling. +The Apify SDK for Python is the official library for creating [Apify Actors](https://docs.apify.com/platform/actors) in Python. It gives you everything you need to build an Actor and run it both locally and on the [Apify platform](https://docs.apify.com/platform), including: + +- **Actor lifecycle management** — initialization, graceful shutdown, status messages, rebooting, and metamorphing. +- **Storage access** — datasets, key-value stores, and request queues, with automatic local emulation when running outside the platform. +- **Actor input** — convenient access to the Actor input, including automatic decryption of secret fields. +- **Events & state persistence** — react to platform events (system info, migration, abort) and persist state across migrations and restarts. +- **Proxy management** — Apify Proxy and custom proxies, with session and tiered-proxy support. +- **Platform interaction** — start, call, and abort other Actors and tasks, create webhooks, and reach the full Apify API client. +- **Monetization** — charge users with the pay-per-event pricing model. +- **Framework integrations** — first-class support for [Crawlee](../guides/crawlee) and [Scrapy](../guides/scrapy), with guides for [Playwright](../guides/playwright) and others. {IntroductionExample} @@ -29,7 +38,7 @@ Explore the Guides section in the sidebar for a deeper understanding of the SDK' ## Installation -The Apify SDK for Python requires Python version 3.10 or above. It is typically installed when you create a new Actor project using the [Apify CLI](https://docs.apify.com/cli). To install it manually in an existing project, use: +The Apify SDK for Python requires Python version 3.11 or above. It is typically installed when you create a new Actor project using the [Apify CLI](https://docs.apify.com/cli). To install it manually in an existing project, use: ```bash pip install apify diff --git a/docs/01_introduction/quick-start.mdx b/docs/01_introduction/quick-start.mdx index da166da96..7d753840e 100644 --- a/docs/01_introduction/quick-start.mdx +++ b/docs/01_introduction/quick-start.mdx @@ -59,7 +59,7 @@ The Actor's runtime dependencies are specified in the `requirements.txt` file, w The Actor's source code is in the `src` folder. This folder contains two important files: - `main.py` - which contains the main function of the Actor -- `__main__.py` - which is the entrypoint of the Actor package setting up the Actor [logger](../concepts/logging) and executing the Actor's main function via [`asyncio.run()`](https://docs.python.org/3/library/asyncio-runner.html#asyncio.run). +- `__main__.py` - which is the entrypoint of the Actor package, executing the Actor's main function via [`asyncio.run()`](https://docs.python.org/3/library/asyncio-runner.html#asyncio.run). @@ -67,7 +67,7 @@ The Actor's source code is in the `src` folder. This folder contains two importa {MainExample} - + {UnderscoreMainExample} @@ -79,13 +79,15 @@ We recommend keeping the entrypoint for the Actor in the `src/__main__.py` file. ## Next steps +Now that you can create and run an Actor locally, explore the rest of the SDK's features and its framework integrations. + ### Concepts To learn more about the features of the Apify SDK and how to use them, check out the Concepts section in the sidebar: - [Actor lifecycle](../concepts/actor-lifecycle) - [Actor input](../concepts/actor-input) -- [Working with storages](../concepts/storages) +- [Storages](../concepts/storages) - [Actor events & state persistence](../concepts/actor-events) - [Proxy management](../concepts/proxy-management) - [Interacting with other Actors](../concepts/interacting-with-other-actors) @@ -94,6 +96,7 @@ To learn more about the features of the Apify SDK and how to use them, check out - [Logging](../concepts/logging) - [Actor configuration](../concepts/actor-configuration) - [Pay-per-event monetization](../concepts/pay-per-event) +- [Storage clients](../concepts/storage-clients) ### Guides diff --git a/docs/02_concepts/01_actor_lifecycle.mdx b/docs/02_concepts/01_actor_lifecycle.mdx index 40826305a..b5acda745 100644 --- a/docs/02_concepts/01_actor_lifecycle.mdx +++ b/docs/02_concepts/01_actor_lifecycle.mdx @@ -106,4 +106,4 @@ Update the status only when the user's understanding of progress changes - avoid ## Conclusion -This page has presented the full Actor lifecycle: initialization, execution, error handling, rebooting, shutdown and status messages. You've seen how the SDK supports both context-based and manual control patterns. For deeper dives, explore the reference docs, [guides](https://docs.apify.com/sdk/python/docs/guides/beautifulsoup-httpx), and [platform documentation](https://docs.apify.com/platform). +This page has presented the full Actor lifecycle: initialization, execution, error handling, rebooting, shutdown and status messages. You've seen how the SDK supports both context-based and manual control patterns. For deeper dives, explore the `Actor` API reference, [guides](../guides/beautifulsoup-httpx), and [platform documentation](https://docs.apify.com/platform). diff --git a/docs/02_concepts/02_actor_input.mdx b/docs/02_concepts/02_actor_input.mdx index 15807c05d..a46210af4 100644 --- a/docs/02_concepts/02_actor_input.mdx +++ b/docs/02_concepts/02_actor_input.mdx @@ -12,7 +12,7 @@ import ApiLink from '@theme/ApiLink'; The Actor gets its [input](https://docs.apify.com/platform/actors/running/input) from the input record in its default [key-value store](https://docs.apify.com/platform/storage/key-value-store). -To access it, instead of reading the record manually, you can use the `Actor.get_input` convenience method. It will get the input record key from the Actor configuration, read the record from the default key-value store,and decrypt any [secret input fields](https://docs.apify.com/platform/actors/development/secret-input). +To access it, instead of reading the record manually, you can use the `Actor.get_input` convenience method. It will get the input record key from the Actor configuration, read the record from the default key-value store, and decrypt any [secret input fields](https://docs.apify.com/platform/actors/development/secret-input). For example, if an Actor received a JSON input with two fields, `{ "firstNumber": 1, "secondNumber": 2 }`, this is how you might process it: @@ -34,4 +34,8 @@ The Apify platform supports [secret input fields](https://docs.apify.com/platfor No special handling is needed in your code — when you call `Actor.get_input`, encrypted fields are automatically decrypted using the Actor's private key, which is provided by the platform via environment variables. You receive the plaintext values directly. +## Conclusion + +This page has shown how to read Actor input with `Actor.get_input`, how to load URL sources with `ApifyRequestList`, and how secret input fields are decrypted automatically when you read them. + For more details on Actor input and how to define input schemas, see the [Actor input](https://docs.apify.com/platform/actors/running/input) and [input schema](https://docs.apify.com/platform/actors/development/input-schema) documentation on the Apify platform. diff --git a/docs/02_concepts/03_storages.mdx b/docs/02_concepts/03_storages.mdx index 059682b2b..b46ff4bb8 100644 --- a/docs/02_concepts/03_storages.mdx +++ b/docs/02_concepts/03_storages.mdx @@ -1,6 +1,6 @@ --- id: storages -title: Working with storages +title: Storages description: Use datasets, key-value stores, and request queues to persist Actor data. --- @@ -45,11 +45,11 @@ Each dataset item, key-value store record, or request in a request queue is then When developing locally, opening any storage will by default use local storage. To change this behavior and to use remote storage you have to use `force_cloud=True` argument in `Actor.open_dataset`, `Actor.open_request_queue` or `Actor.open_key_value_store`. Proper use of this argument allows you to work with both local and remote storages. -Calling another remote Actor and accessing its default storage is typical use-case for using `force-cloud=True` argument to open remote Actor's storages. +Calling another remote Actor and accessing its default storage is a typical use-case for using `force_cloud=True` argument to open remote Actor's storages. ### Local storage persistence -By default, the storage contents are persisted across multiple Actor runs. To clean up the Actor storages before the running the Actor, use the `--purge` flag of the [`apify run`](https://docs.apify.com/cli/docs/reference#apify-run) command of the Apify CLI. +By default, the storage contents are persisted across multiple Actor runs. To clean up the Actor storages before running the Actor, use the `--purge` flag of the [`apify run`](https://docs.apify.com/cli/docs/reference#apify-run) command of the Apify CLI. ```bash apify run --purge @@ -106,8 +106,8 @@ To get an iterator of the data, you can use the `Dataset.export_to_csv` -or `Dataset.export_to_json` method. +using the `Dataset.export_to` method with the +`content_type` argument set to `'csv'` or `'json'`. {DatasetExportsExample} @@ -183,6 +183,10 @@ To check if all the requests in the queue are handled, you can use the @@ -25,25 +27,23 @@ During its runtime, the Actor receives Actor events sent by the Apify platform o SYSTEM_INFO -
{`{
-  "created_at": datetime,
-  "cpu_current_usage": float,
-  "mem_current_bytes": int,
-  "is_cpu_overloaded": bool
-}`}
-            
+ EventSystemInfoData -

This event is emitted regularly and it indicates the current resource usage of the Actor.

- The is_cpu_overloaded argument indicates whether the current CPU usage is higher than Config.max_used_cpu_ratio +

Emitted regularly to report the Actor's current resource usage. The + cpu_info.used_ratio field reports the fraction of CPU currently in use + (a float between 0.0 and 1.0), and memory_info.current_size + reports the current memory usage. Compare cpu_info.used_ratio against + Configuration.max_used_cpu_ratio to detect CPU overload.

MIGRATING - None + EventMigratingData

Emitted when the Actor running on the Apify platform is going to be migrated - {' '}to another worker server soon.

+ {' '}to another worker server soon. The time_remaining field reports how much time + the Actor has left before it is force-migrated.

You can use it to persist the state of the Actor so that once it is executed again on the new server, it doesn't have to start over from the beginning. Once you have persisted the state of your Actor, you can call `Actor.reboot` @@ -52,7 +52,7 @@ During its runtime, the Actor receives Actor events sent by the Apify platform o ABORTING - None + EventAbortingData 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. @@ -61,7 +61,7 @@ During its runtime, the Actor receives Actor events sent by the Apify platform o PERSIST_STATE -
{`{ "is_migrating": bool }`}
+ EventPersistStateData

Emitted in regular intervals (by default 60 seconds) to notify the Actor that it should persist its state, in order to avoid repeating all work when the Actor restarts.

@@ -73,7 +73,7 @@ During its runtime, the Actor receives Actor events sent by the Apify platform o EXIT - None + EventExitData Emitted by the SDK (not the platform) when the Actor is about to exit. You can use this event to perform final cleanup tasks, such as closing external connections or sending notifications, before the Actor shuts down. @@ -103,4 +103,8 @@ You can optionally specify a `key` (the key-value store key under which the stat {UseStateExample}
+## Conclusion + +This page has described the events emitted during a run — `SYSTEM_INFO`, `MIGRATING`, `ABORTING`, `PERSIST_STATE`, and `EXIT` — how to handle them with `Actor.on`, and how to persist state automatically with `Actor.use_state`. + For more details on platform events and state persistence, see the [system events](https://docs.apify.com/platform/actors/development/programming-interface/system-events) and [state persistence](https://docs.apify.com/platform/actors/development/state-persistence) documentation on the Apify platform. diff --git a/docs/02_concepts/05_proxy_management.mdx b/docs/02_concepts/05_proxy_management.mdx index d60763b5c..482801e13 100644 --- a/docs/02_concepts/05_proxy_management.mdx +++ b/docs/02_concepts/05_proxy_management.mdx @@ -22,7 +22,7 @@ The Apify SDK provides built-in proxy management through the {ApifyProxyExample} @@ -38,7 +38,7 @@ If you want to use Apify Proxy locally, make sure that you run your Actors via t All your proxy needs are managed by the `ProxyConfiguration` class. You create an instance using the `Actor.create_proxy_configuration()` method. Then you generate proxy URLs using the `ProxyConfiguration.new_url()` method. -### Apify proxy vs. your own proxies +### Apify Proxy vs. your own proxies The `ProxyConfiguration` class covers both Apify Proxy and custom proxy URLs, so that you can easily switch between proxy providers. However, some features of the class are available only to Apify Proxy users, mainly because Apify Proxy is what one would call a super-proxy. It's not a single proxy server, but an API endpoint that allows connection through millions of different IP addresses. So the class essentially has two modes: Apify Proxy or Your proxy. @@ -54,7 +54,7 @@ When no `session_id` is provided, your custom proxy URLs are rotated round-robin {ProxyRotationExample} -### Apify proxy configuration +### Apify Proxy configuration With Apify Proxy, you can select specific proxy groups to use, or countries to connect from. For even finer control, you can also target a specific subdivision (e.g. a US state) using the `subdivision_code` parameter alongside `country_code`. This allows you to get better proxy performance after some initial research. @@ -106,6 +106,8 @@ You can then use that input to create the proxy configuration: ## Using the generated proxy URLs +`ProxyConfiguration` only generates proxy URLs — it does not make requests itself. Pass a generated URL to whichever HTTP client your Actor uses to route requests through the proxy. + ### HTTPX To use the generated proxy URLs with the `httpx` library, use the [`proxies`](https://www.python-httpx.org/advanced/#http-proxying) argument: @@ -120,4 +122,8 @@ Make sure you have the `httpx` library installed: pip install httpx ``` +## Conclusion + +This page has explained how to manage proxies with the `ProxyConfiguration` class — using Apify Proxy or your own servers, keeping sessions sticky across requests, configuring tiered proxy rotation, and feeding proxy settings from Actor input. + For full details on proxy configuration options, see the `ProxyConfiguration` API reference and the [Apify Proxy documentation](https://docs.apify.com/proxy). diff --git a/docs/02_concepts/06_interacting_with_other_actors.mdx b/docs/02_concepts/06_interacting_with_other_actors.mdx index cb28d7cf9..f8600f62a 100644 --- a/docs/02_concepts/06_interacting_with_other_actors.mdx +++ b/docs/02_concepts/06_interacting_with_other_actors.mdx @@ -63,4 +63,8 @@ When you set `gracefully=True`, the platform sends `ABORTING` and `PERSIST_STATE {InteractingAbortExample} +## Conclusion + +This page has shown how to interact with other Actors from your code — starting a run with `Actor.start`, waiting for it to finish with `Actor.call` or `Actor.call_task`, transforming a run with `Actor.metamorph`, and stopping one with `Actor.abort`. + For the full list of methods for interacting with other Actors, see the `Actor` API reference. For more details on running Actors and Actor tasks on the platform, see the [Actors](https://docs.apify.com/platform/actors) and [Actor tasks](https://docs.apify.com/platform/actors/tasks) documentation. diff --git a/docs/02_concepts/07_webhooks.mdx b/docs/02_concepts/07_webhooks.mdx index 5016d8a8a..44e7dc1e0 100644 --- a/docs/02_concepts/07_webhooks.mdx +++ b/docs/02_concepts/07_webhooks.mdx @@ -32,4 +32,8 @@ To ensure that duplicate ad-hoc webhooks won't get created in a case of Actor re {WebhookPreventingExample} +## Conclusion + +This page has shown how to create ad-hoc webhooks dynamically with `Actor.add_webhook` and how to avoid creating duplicates across Actor restarts using the `idempotency_key` parameter. + For more information about webhooks, including event types and payloads, see the [Apify webhooks documentation](https://docs.apify.com/platform/integrations/webhooks). diff --git a/docs/02_concepts/08_access_apify_api.mdx b/docs/02_concepts/08_access_apify_api.mdx index 5c4ba7ae7..66174e780 100644 --- a/docs/02_concepts/08_access_apify_api.mdx +++ b/docs/02_concepts/08_access_apify_api.mdx @@ -12,9 +12,11 @@ import ActorNewClientExample from '!!raw-loader!roa-loader!./code/08_actor_new_c The Apify SDK provides a built-in instance of the [Apify API Client](https://docs.apify.com/api/client/python) for accessing Apify platform features beyond what the SDK covers directly. +The SDK wraps the most common operations — opening storages, reading input, charging, and starting other Actors — in convenient high-level methods. When you need something it does not expose directly, such as managing schedules, listing your Actors and runs, working with builds or webhook dispatches, or reading another run's dataset, you can reach the full [Apify API](https://docs.apify.com/api/v2) through the client. It provides a dedicated sub-client for each API resource — among them `dataset`, `key_value_store`, `request_queue`, `run`, `actor`, `task`, `schedule`, `webhook`, and `user` — and each operation returns plain Python data structures. + ## Actor client -To access the provided instance of [`ApifyClientAsync`](https://docs.apify.com/api/client/python/reference/class/ApifyClientAsync), you can use the `Actor.apify_client` property. +To access the provided instance of [`ApifyClientAsync`](https://docs.apify.com/api/client/python/reference/class/ApifyClientAsync), you can use the `Actor.apify_client` property. This instance is already authenticated with the Actor's API token and points at the same API the Actor runs against, so it is ready to use immediately. For example, to get the details of your user, you can use this snippet: @@ -22,12 +24,20 @@ For example, to get the details of your user, you can use this snippet: {ActorClientExample} +You select a resource with the matching method — for example `Actor.apify_client.dataset('')` for a dataset or `Actor.apify_client.run('')` for an Actor run — and then call the operation you need on the returned sub-client. + ## Actor new client -If you want to create a completely new instance of the client, for example, to get a client for a different user or change the configuration of the client, you can use the `Actor.new_client` method: +If you want to create a completely new instance of the client — for example, to use a different user's token or change the client configuration — you can use the `Actor.new_client` method. It accepts an optional `token` and `api_url`, along with retry and timeout settings (`max_retries`, `min_delay_between_retries`, `timeout`), and returns a fresh `ApifyClientAsync`: {ActorNewClientExample} +This is useful when the Actor's own token is not the right one — for instance, when acting on behalf of another user — or when you want different retry and timeout behavior than the shared `Actor.apify_client` instance. + +## Conclusion + +This page has shown how to reach the Apify API directly — through the built-in client exposed by `Actor.apify_client`, or a freshly configured one created with `Actor.new_client` — for platform features the SDK does not wrap directly. + For the full API client documentation, see the [Apify API Client for Python](https://docs.apify.com/api/client/python). diff --git a/docs/02_concepts/09_logging.mdx b/docs/02_concepts/09_logging.mdx index b2066053a..5530656d2 100644 --- a/docs/02_concepts/09_logging.mdx +++ b/docs/02_concepts/09_logging.mdx @@ -20,6 +20,8 @@ When you create an Actor from an Apify-provided template, either in Apify Consol ## Manual configuration +If you are not using an Apify template — or you want to override what it sets up — you can configure the log level and the log formatting yourself. + ### Configuring the log level In Python's default behavior, if you don't configure the logger otherwise, only logs with level `WARNING` or higher are printed out to the standard output, without any formatting. To also have logs with `DEBUG` and `INFO` level printed out, you need to call the [`Logger.setLevel`](https://docs.python.org/3/library/logging.html#logging.Logger.setLevel) method on the logger, with the desired minimum level as an argument. @@ -99,11 +101,11 @@ Typical use case for log redirection is to call another Actor using the -Each default redirect logger log entry will have a specific format. After the timestamp, it will contain cyan colored text that will contain the redirect information - the other actor's name and the run ID. The rest of the log message will be printed in the same manner as the parent Actor's logger is configured. +Each default redirect logger log entry will have a specific format. After the timestamp, it will contain cyan colored text that will contain the redirect information - the other Actor's name and the run ID. The rest of the log message will be printed in the same manner as the parent Actor's logger is configured. -The log redirection can be deep, meaning that if the other actor also starts another actor and is redirecting logs from it, then in the top-level Actor, you can see it as well. See the following example screenshot of the Apify log console when one actor recursively starts itself (there are 2 levels of recursion in the example). +The log redirection can be deep, meaning that if the other Actor also starts another Actor and is redirecting logs from it, then in the top-level Actor, you can see it as well. See the following example screenshot of the Apify log console when one Actor recursively starts itself (there are 2 levels of recursion in the example). -![Console with redirected logs](/img/guides/redirected_logs_example.webp 'Example of console with redirected logs from recursively started actor.') +![Console with redirected logs](/img/guides/redirected_logs_example.webp 'Example of console with redirected logs from recursively started Actor.') ### Redirecting logs from already running Actor run @@ -114,3 +116,7 @@ You can further decide whether you want to redirect just new logs of the ongoing {RedirectLogExistingRun} + +## Conclusion + +This page has covered how the SDK logs through the `apify` logger — setting the log level, formatting output with `ActorLogFormatter`, using the logger at each level, and redirecting logs from other Actor runs back into the parent run. For more on the underlying logging machinery, see Python's standard [`logging`](https://docs.python.org/3/library/logging.html) module documentation. diff --git a/docs/02_concepts/10_configuration.mdx b/docs/02_concepts/10_configuration.mdx index 6296b864b..16c3321a1 100644 --- a/docs/02_concepts/10_configuration.mdx +++ b/docs/02_concepts/10_configuration.mdx @@ -27,14 +27,29 @@ This will cause the Actor to persist its state every 10 seconds: ## Configuring via environment variables -All the configuration options can be set via environment variables. The environment variables are prefixed with `APIFY_`, and the configuration options are in uppercase, with underscores as separators. See the `Configuration` API reference for the full list of configuration options. +All configuration options can also be set via environment variables. Most options are read from an environment variable named after the option in uppercase; many options accept several aliases — commonly with an `APIFY_`, `ACTOR_`, or `CRAWLEE_` prefix. See the `Configuration` API reference for the full list of configuration options. -This Actor run will not persist its local storages to the filesystem: +For example, this Actor run will keep the contents of its local storages instead of purging them on start: ```bash -APIFY_PERSIST_STORAGE=0 apify run +APIFY_PURGE_ON_START=0 apify run ``` +### Commonly used options + +The table below lists a few options you are most likely to set yourself. When running on the Apify platform or via the Apify CLI, the platform-related options are populated automatically. + +| Option | Environment variable | Default | Description | +| --- | --- | --- | --- | +| `token` | `APIFY_TOKEN` | `None` | API token used to authenticate calls to the Apify API. | +| `proxy_password` | `APIFY_PROXY_PASSWORD` | `None` | Password for [Apify Proxy](https://docs.apify.com/proxy). | +| `purge_on_start` | `APIFY_PURGE_ON_START` | `True` | Whether to purge local storages when the Actor starts. | +| `persist_state_interval` | `APIFY_PERSIST_STATE_INTERVAL_MILLIS` | `1 min` | How often the `PERSIST_STATE` event is emitted (the variable is in milliseconds). | +| `log_level` | `APIFY_LOG_LEVEL` | `'INFO'` | Minimum severity of log messages that are printed. | +| `headless` | `APIFY_HEADLESS` | `True` | Whether to run browsers in headless mode. | +| `storage_dir` | `APIFY_LOCAL_STORAGE_DIR` | `'./storage'` | Directory holding local storages when running outside the platform. | +| `is_at_home` | `APIFY_IS_AT_HOME` | `False` | Set by the platform — `True` when the Actor runs on Apify. | + ## Reading the runtime environment The `Actor.get_env` method returns a dictionary with all `APIFY_*` environment variables parsed into their typed values. This is useful for inspecting the Actor's runtime context, such as the Actor ID, run ID, or default storage IDs. Variables that are not set or are invalid will have a value of `None`. @@ -51,4 +66,8 @@ The `Actor.is_at_home` method ret {PlatformDetectionExample} +## Conclusion + +This page has shown how to configure an Actor through the `Configuration` class or environment variables, which options you are most likely to set yourself, and how to inspect the runtime environment with `Actor.get_env` and `Actor.is_at_home`. + For the full list of configuration options, see the `Configuration` API reference. For a complete list of environment variables available on the platform, see the [environment variables](https://docs.apify.com/platform/actors/development/programming-interface/environment-variables) documentation. diff --git a/docs/02_concepts/11_pay_per_event.mdx b/docs/02_concepts/11_pay_per_event.mdx index d8c04443e..bf825ae40 100644 --- a/docs/02_concepts/11_pay_per_event.mdx +++ b/docs/02_concepts/11_pay_per_event.mdx @@ -13,7 +13,7 @@ import RunnableCodeBlock from '@site/src/components/RunnableCodeBlock'; Apify provides several [pricing models](https://docs.apify.com/platform/actors/publishing/monetize) for monetizing your Actors. The most recent and most flexible one is [pay-per-event](https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event), which lets you charge your users programmatically directly from your Actor. As the name suggests, you may charge the users each time a specific event occurs, for example a call to an external API or when you return a result. -To use the pay-per-event pricing model, you first need to [set it up](https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event) for your Actor in the Apify console. After that, you're free to start charging for events. +To use the pay-per-event pricing model, you first need to [set it up](https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event) for your Actor in the Apify Console. After that, you're free to start charging for events. :::info How pay-per-event pricing works @@ -23,7 +23,7 @@ If you want more details about PPE pricing, please refer to our [PPE documentati ## Charging for events -After monetization is set in the Apify console, you can add `Actor.charge` calls to your code and start monetizing! +After monetization is set in the Apify Console, you can add `Actor.charge` calls to your code and start monetizing! {ActorChargeSource} @@ -31,7 +31,7 @@ After monetization is set in the Apify console, you can add `Actor.get_charging_manager()` to access the `ChargingManager`, which can provide more detailed information - for example how many events of each type can be charged before reaching the configured limit. +If you need finer control over charging, you can call `Actor.get_charging_manager()` to access the `ChargingManager`, which can provide more detailed information - for example how many events of each type can be charged before reaching the configured limit. ### Handling the charge limit @@ -59,7 +59,7 @@ For budget-aware crawling strategies, the `C ## Transitioning from a different pricing model -When you plan to start using the pay-per-event pricing model for an Actor that is already monetized with a different pricing model, your source code will need support both pricing models during the transition period enforced by the Apify platform. Arguably the most frequent case is the transition from the pay-per-result model which utilizes the `ACTOR_MAX_PAID_DATASET_ITEMS` environment variable to prevent returning unpaid dataset items. The following is an example how to handle such scenarios. The key part is the `ChargingManager.get_pricing_info()` method which returns information about the current pricing model. +When you plan to start using the pay-per-event pricing model for an Actor that is already monetized with a different pricing model, your source code will need to support both pricing models during the transition period enforced by the Apify platform. Arguably the most frequent case is the transition from the pay-per-result model which utilizes the `ACTOR_MAX_PAID_DATASET_ITEMS` environment variable to prevent returning unpaid dataset items. The following is an example how to handle such scenarios. The key part is the `ChargingManager.get_pricing_info()` method which returns information about the current pricing model. {ConditionalActorChargeSource} @@ -77,4 +77,8 @@ If you also wish to see a log of all the events charged throughout the run, the Because pricing configuration is stored by the Apify platform, all events will have a default price of $1. +## Conclusion + +This page has covered the pay-per-event pricing model — charging for events with `Actor.charge`, respecting the charge limit so your Actor stops once the budget is exhausted, querying the `ChargingManager`, handling the transition from another pricing model, and testing charging locally. + For comprehensive details on pay-per-event pricing and Actor monetization, see the [pay-per-event](https://docs.apify.com/platform/actors/publishing/monetize/pay-per-event) and [monetization](https://docs.apify.com/platform/actors/publishing/monetize) documentation on the Apify platform. diff --git a/docs/02_concepts/12_storage_clients.mdx b/docs/02_concepts/12_storage_clients.mdx new file mode 100644 index 000000000..f4ea5a876 --- /dev/null +++ b/docs/02_concepts/12_storage_clients.mdx @@ -0,0 +1,72 @@ +--- +id: storage-clients +title: Storage clients +description: Choose and configure the backend the Actor uses for datasets, key-value stores, and request queues. +--- + +import RunnableCodeBlock from '@site/src/components/RunnableCodeBlock'; +import ApiLink from '@theme/ApiLink'; + +import SharedRequestQueueExample from '!!raw-loader!roa-loader!./code/12_shared_request_queue.py'; +import CustomStorageClientExample from '!!raw-loader!roa-loader!./code/12_custom_storage_client.py'; + +Storage clients are the components that actually read and write your [storages](./storages) — datasets, key-value stores, and request queues. The Apify SDK selects an appropriate client automatically based on where the Actor runs, so for most Actors you never need to think about them. This page explains the available clients and how to customize them when you do. + +## How the Actor selects a storage client + +By default, the Actor uses a `SmartApifyStorageClient` — a hybrid client that delegates to one of two underlying clients depending on the environment: + +- When running **on the Apify platform** (detected automatically), or when you pass `force_cloud=True`, it uses the **cloud** client — `ApifyStorageClient`, which persists data through the Apify API. +- When running **locally**, it uses the **local** client — `FileSystemStorageClient`, which emulates platform storages on your filesystem under the `storage` folder. + +This is what lets the same Actor code run unchanged both locally and on the platform. + +## Available storage clients + +The `apify.storage_clients` module provides the following clients: + +- `SmartApifyStorageClient` — the default hybrid client described above. It wraps a `cloud_storage_client` and a `local_storage_client` and routes each call to the right one. +- `ApifyStorageClient` — talks to the Apify API. Used as the cloud client. +- `FileSystemStorageClient` — persists data to the local filesystem. Used as the default local client. +- `MemoryStorageClient` — keeps everything in memory only; nothing is persisted. Useful for tests and short-lived runs. + +All of these implement Crawlee's `StorageClient` interface, so any of them can be used as a sub-client of `SmartApifyStorageClient` — see [customizing the storage client](#customizing-the-storage-client) below. + +Crawlee additionally ships storage clients backed by a self-hosted database — a [`RedisStorageClient`](https://crawlee.dev/python/api/class/RedisStorageClient) and a [`SqlStorageClient`](https://crawlee.dev/python/api/class/SqlStorageClient). The Apify SDK does not re-export these, because they each require an extra dependency that the SDK does not install. To use one, install the matching Crawlee extra (for example `pip install 'crawlee[redis]'` or `crawlee[sql-postgres]` / `crawlee[sql-sqlite]`), import the client from `crawlee.storage_clients`, and pass it as a sub-client of `SmartApifyStorageClient`. See the [Crawlee storage clients guide](https://crawlee.dev/python/docs/guides/storage-clients) for details. + +## Single vs. shared request queue + +`ApifyStorageClient` supports two ways of accessing the Apify request queue, selected via its `request_queue_access` argument: + +- **`'single'`** (default) — optimized for a single consumer. It makes far fewer API calls, so it is cheaper and faster, but it does not support multiple clients consuming the same queue concurrently. This is the right choice for the majority of Actors. +- **`'shared'`** — supports multiple consumers working on the same queue at the same time, at the cost of more API calls. + +To opt into the shared client, set it as the cloud client of the `SmartApifyStorageClient` in the [service locator](https://crawlee.dev/python/docs/guides/service-locator) before entering the Actor context: + + + {SharedRequestQueueExample} + + +## Using cloud storage while running locally + +When developing locally, storages are read from and written to the local filesystem by default. To work with a storage on the Apify platform instead — for example, to read the output of a remote Actor run — pass `force_cloud=True` to `Actor.open_dataset`, `Actor.open_key_value_store`, or `Actor.open_request_queue`. This requires an Apify token, provided via the `APIFY_TOKEN` environment variable. + +## Customizing the storage client + +You can replace either of the underlying clients — for example, to keep all local data in memory instead of on disk. To do this, set a `SmartApifyStorageClient` with your chosen sub-clients in the service locator **before** entering the Actor context (or awaiting `Actor.init`): + + + {CustomStorageClientExample} + + +:::note + +The Actor's storage client must be a `SmartApifyStorageClient`. Setting a bare `ApifyStorageClient` or `MemoryStorageClient` directly in the service locator raises an error — wrap it in a `SmartApifyStorageClient` as shown above. + +::: + +## Conclusion + +This page has explained how the Actor selects a storage client, the clients available in the `apify.storage_clients` module, the difference between the single and shared request-queue clients, and how to customize the client through the service locator. + +For a deeper look at how storage clients work and how to write your own, see the [Crawlee storage clients guide](https://crawlee.dev/python/docs/guides/storage-clients). diff --git a/docs/02_concepts/code/04_actor_events.py b/docs/02_concepts/code/04_actor_events.py index 591fddcd0..555c61b5d 100644 --- a/docs/02_concepts/code/04_actor_events.py +++ b/docs/02_concepts/code/04_actor_events.py @@ -1,7 +1,6 @@ import asyncio -from typing import Any -from apify import Actor, Event +from apify import Actor, Event, EventPersistStateData async def main() -> None: @@ -15,9 +14,11 @@ async def main() -> None: processed_items = actor_state # Save the state when the `PERSIST_STATE` event happens - async def save_state(event_data: Any) -> None: + async def save_state(event_data: EventPersistStateData) -> None: nonlocal processed_items - Actor.log.info('Saving Actor state', extra=event_data) + Actor.log.info( + 'Persisting Actor state (migrating=%s)', event_data.is_migrating + ) await Actor.set_value('STATE', processed_items) Actor.on(Event.PERSIST_STATE, save_state) diff --git a/docs/02_concepts/code/12_custom_storage_client.py b/docs/02_concepts/code/12_custom_storage_client.py new file mode 100644 index 000000000..1e313439a --- /dev/null +++ b/docs/02_concepts/code/12_custom_storage_client.py @@ -0,0 +1,23 @@ +import asyncio + +from crawlee import service_locator + +from apify import Actor +from apify.storage_clients import MemoryStorageClient, SmartApifyStorageClient + + +async def main() -> None: + # Keep all local data in memory instead of writing it to the filesystem + # when running outside the Apify platform. + local_storage_client = MemoryStorageClient() + service_locator.set_storage_client( + SmartApifyStorageClient(local_storage_client=local_storage_client), + ) + + async with Actor: + store = await Actor.open_key_value_store() + await store.set_value('example', {'hello': 'world'}) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/docs/02_concepts/code/12_shared_request_queue.py b/docs/02_concepts/code/12_shared_request_queue.py new file mode 100644 index 000000000..a7c22746e --- /dev/null +++ b/docs/02_concepts/code/12_shared_request_queue.py @@ -0,0 +1,23 @@ +import asyncio + +from crawlee import service_locator + +from apify import Actor +from apify.storage_clients import ApifyStorageClient, SmartApifyStorageClient + + +async def main() -> None: + # Use the shared Apify request queue client, which supports multiple + # consumers working on the same queue at the cost of more API calls. + cloud_storage_client = ApifyStorageClient(request_queue_access='shared') + service_locator.set_storage_client( + SmartApifyStorageClient(cloud_storage_client=cloud_storage_client), + ) + + async with Actor: + request_queue = await Actor.open_request_queue() + await request_queue.add_request('https://crawlee.dev') + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/docs/04_upgrading/upgrading_to_v2.md b/docs/04_upgrading/upgrading_to_v2.md index 2269cda42..313183927 100644 --- a/docs/04_upgrading/upgrading_to_v2.md +++ b/docs/04_upgrading/upgrading_to_v2.md @@ -16,7 +16,7 @@ Support for Python 3.8 has been dropped. The Apify Python SDK v2.x now requires - There is a difference in the `RequestQueue.add_request` method: it accepts an `apify.Request` object instead of a free-form dictionary. - A quick way to migrate from dict-based arguments is to wrap it with a `Request.model_validate()` call. - The preferred way is using the `Request.from_url` helper which prefills the `unique_key` and `id` attributes, or instantiating it directly, e.g., `Request(url='https://example.tld', ...)`. - - For simple use cases, `add_request` also accepts plain strings that contain an URL, e.g. `queue.add_request('https://example.tld')`. + - For simple use cases, `add_request` also accepts plain strings that contain a URL, e.g. `queue.add_request('https://example.tld')`. - Removing the `StorageClientManager` class is a significant change. If you need to change the storage client, use `crawlee.service_container` instead. ## Configuration @@ -28,8 +28,8 @@ Attributes suffixed with `_millis` were renamed to remove said suffix and have t ## Actor - The `Actor.main` method has been removed as it brings no benefits compared to using `async with Actor`. -- The `Actor.add_webhook`, `Actor.start`, `Actor.call` and `Actor.start_task` methods now accept instances of the `apify.Webhook` model instead of an untyped `dict`. -- `Actor.start`, `Actor.call`, `Actor.start_task`, `Actor.set_status_message` and `Actor.abort` return instances of the `ActorRun` model instead of an untyped `dict`. +- The `Actor.add_webhook`, `Actor.start`, `Actor.call` and `Actor.call_task` methods now accept instances of the `apify.Webhook` model instead of an untyped `dict`. +- `Actor.start`, `Actor.call`, `Actor.call_task`, `Actor.set_status_message` and `Actor.abort` return instances of the `ActorRun` model instead of an untyped `dict`. - Upon entering the context manager (`async with Actor`), the `Actor` puts the default logging configuration in place. This can be disabled using the `configure_logging` parameter. - The `config` parameter of `Actor` has been renamed to `configuration`. - Event handlers registered via `Actor.on` will now receive Pydantic objects instead of untyped dicts. For example, where you would do `event['isMigrating']`, you should now use `event.is_migrating` diff --git a/docs/04_upgrading/upgrading_to_v3.md b/docs/04_upgrading/upgrading_to_v3.md index 729ad68b8..a4306a507 100644 --- a/docs/04_upgrading/upgrading_to_v3.md +++ b/docs/04_upgrading/upgrading_to_v3.md @@ -110,9 +110,11 @@ async def main(): ) ``` -### Changes in storage clients +## Changes in storage clients -## Explicit control over storage clients used in Actor +Apify SDK v3.0 also reworks how storage clients are configured, giving you explicit control over which client the `Actor` uses. + +### Explicit control over storage clients used in Actor - It is now possible to have full control over which storage clients are used by the `Actor`. To make development of Actors convenient, the `Actor` has two storage clients. One that is used when running on Apify platform or when opening storages with `force_cloud=True` and the other client that is used when running outside the Apify platform. The `Actor` has reasonable defaults and for the majority of use-cases there is no need to change it. However, if you need to use a different storage client, you can set it up before entering `Actor` context through `service_locator`. **Now (v3.0):** @@ -135,7 +137,7 @@ async def main(): ``` -## The default use of optimized ApifyRequestQueueClient +### The default use of optimized ApifyRequestQueueClient - The default client for working with Apify platform based `RequestQueue` is now optimized and simplified client which does significantly lower amount of API calls, but does not support multiple consumers working on the same queue. It is cheaper and faster and is suitable for the majority of the use cases. - The full client is still available, but it has to be explicitly requested via `request_queue_access="shared"` argument when using the `ApifyStorageClient`. diff --git a/docs/04_upgrading/upgrading_to_v4.md b/docs/04_upgrading/upgrading_to_v4.md index e62ae02ba..34a26242b 100644 --- a/docs/04_upgrading/upgrading_to_v4.md +++ b/docs/04_upgrading/upgrading_to_v4.md @@ -6,7 +6,7 @@ description: Breaking changes and migration guide from Apify SDK v3.x to v4.0. This guide lists the breaking changes between Apify Python SDK v3.x and v4.0. -## Python 3.11+ required +## Python version support Support for Python 3.10 has been dropped. The Apify Python SDK v4.x now requires Python 3.11 or later — make sure your environment is on a compatible version before upgrading. diff --git a/src/apify/storage_clients/__init__.py b/src/apify/storage_clients/__init__.py index 8a62e3dc8..fef5dde83 100644 --- a/src/apify/storage_clients/__init__.py +++ b/src/apify/storage_clients/__init__.py @@ -1,4 +1,4 @@ -from crawlee.storage_clients import MemoryStorageClient +from crawlee.storage_clients import MemoryStorageClient, StorageClient from ._apify import ApifyStorageClient from ._file_system import ApifyFileSystemStorageClient as FileSystemStorageClient @@ -9,4 +9,5 @@ 'FileSystemStorageClient', 'MemoryStorageClient', 'SmartApifyStorageClient', + 'StorageClient', ] diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 2583d8515..d6ef5fd68 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -259,10 +259,6 @@ module.exports = { url: 'https://crawlee.dev/python/api/class/FileSystemStorageClient', group: 'Storage clients', }, - { - url: 'https://crawlee.dev/python/api/class/SqlStorageClient', - group: 'Storage clients', - }, // Request loaders { url: 'https://crawlee.dev/python/api/class/RequestLoader', From 35be39485e051a9a96dcb01dd76de91302bac427 Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Mon, 8 Jun 2026 13:44:20 +0200 Subject: [PATCH 02/10] docs: reduce clause-gluing dashes in the SDK docs prose --- docs/02_concepts/03_storages.mdx | 4 ++-- docs/02_concepts/04_actor_events.mdx | 4 ++-- docs/02_concepts/05_proxy_management.mdx | 4 ++-- .../06_interacting_with_other_actors.mdx | 2 +- docs/02_concepts/08_access_apify_api.mdx | 10 +++++----- docs/02_concepts/09_logging.mdx | 4 ++-- docs/02_concepts/10_configuration.mdx | 4 ++-- docs/02_concepts/11_pay_per_event.mdx | 2 +- docs/02_concepts/12_storage_clients.mdx | 18 +++++++++--------- 9 files changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/02_concepts/03_storages.mdx b/docs/02_concepts/03_storages.mdx index b46ff4bb8..8bbc6eccc 100644 --- a/docs/02_concepts/03_storages.mdx +++ b/docs/02_concepts/03_storages.mdx @@ -183,10 +183,10 @@ To check if all the requests in the queue are handled, you can use the @@ -105,6 +105,6 @@ You can optionally specify a `key` (the key-value store key under which the stat ## Conclusion -This page has described the events emitted during a run — `SYSTEM_INFO`, `MIGRATING`, `ABORTING`, `PERSIST_STATE`, and `EXIT` — how to handle them with `Actor.on`, and how to persist state automatically with `Actor.use_state`. +This page has described the events emitted during a run (`SYSTEM_INFO`, `MIGRATING`, `ABORTING`, `PERSIST_STATE`, and `EXIT`): how to handle them with `Actor.on`, and how to persist state automatically with `Actor.use_state`. For more details on platform events and state persistence, see the [system events](https://docs.apify.com/platform/actors/development/programming-interface/system-events) and [state persistence](https://docs.apify.com/platform/actors/development/state-persistence) documentation on the Apify platform. diff --git a/docs/02_concepts/05_proxy_management.mdx b/docs/02_concepts/05_proxy_management.mdx index 482801e13..32a15d364 100644 --- a/docs/02_concepts/05_proxy_management.mdx +++ b/docs/02_concepts/05_proxy_management.mdx @@ -106,7 +106,7 @@ You can then use that input to create the proxy configuration: ## Using the generated proxy URLs -`ProxyConfiguration` only generates proxy URLs — it does not make requests itself. Pass a generated URL to whichever HTTP client your Actor uses to route requests through the proxy. +`ProxyConfiguration` only generates proxy URLs. It does not make requests itself. Pass a generated URL to whichever HTTP client your Actor uses to route requests through the proxy. ### HTTPX @@ -124,6 +124,6 @@ pip install httpx ## Conclusion -This page has explained how to manage proxies with the `ProxyConfiguration` class — using Apify Proxy or your own servers, keeping sessions sticky across requests, configuring tiered proxy rotation, and feeding proxy settings from Actor input. +This page has explained how to manage proxies with the `ProxyConfiguration` class: using Apify Proxy or your own servers, keeping sessions sticky across requests, configuring tiered proxy rotation, and feeding proxy settings from Actor input. For full details on proxy configuration options, see the `ProxyConfiguration` API reference and the [Apify Proxy documentation](https://docs.apify.com/proxy). diff --git a/docs/02_concepts/06_interacting_with_other_actors.mdx b/docs/02_concepts/06_interacting_with_other_actors.mdx index f8600f62a..f7b3fd332 100644 --- a/docs/02_concepts/06_interacting_with_other_actors.mdx +++ b/docs/02_concepts/06_interacting_with_other_actors.mdx @@ -65,6 +65,6 @@ When you set `gracefully=True`, the platform sends `ABORTING` and `PERSIST_STATE ## Conclusion -This page has shown how to interact with other Actors from your code — starting a run with `Actor.start`, waiting for it to finish with `Actor.call` or `Actor.call_task`, transforming a run with `Actor.metamorph`, and stopping one with `Actor.abort`. +This page has shown how to interact with other Actors from your code: starting a run with `Actor.start`, waiting for it to finish with `Actor.call` or `Actor.call_task`, transforming a run with `Actor.metamorph`, and stopping one with `Actor.abort`. For the full list of methods for interacting with other Actors, see the `Actor` API reference. For more details on running Actors and Actor tasks on the platform, see the [Actors](https://docs.apify.com/platform/actors) and [Actor tasks](https://docs.apify.com/platform/actors/tasks) documentation. diff --git a/docs/02_concepts/08_access_apify_api.mdx b/docs/02_concepts/08_access_apify_api.mdx index 66174e780..a06a0ad73 100644 --- a/docs/02_concepts/08_access_apify_api.mdx +++ b/docs/02_concepts/08_access_apify_api.mdx @@ -12,7 +12,7 @@ import ActorNewClientExample from '!!raw-loader!roa-loader!./code/08_actor_new_c The Apify SDK provides a built-in instance of the [Apify API Client](https://docs.apify.com/api/client/python) for accessing Apify platform features beyond what the SDK covers directly. -The SDK wraps the most common operations — opening storages, reading input, charging, and starting other Actors — in convenient high-level methods. When you need something it does not expose directly, such as managing schedules, listing your Actors and runs, working with builds or webhook dispatches, or reading another run's dataset, you can reach the full [Apify API](https://docs.apify.com/api/v2) through the client. It provides a dedicated sub-client for each API resource — among them `dataset`, `key_value_store`, `request_queue`, `run`, `actor`, `task`, `schedule`, `webhook`, and `user` — and each operation returns plain Python data structures. +The SDK wraps the most common operations (opening storages, reading input, charging, and starting other Actors) in convenient high-level methods. When you need something it does not expose directly, such as managing schedules, listing your Actors and runs, working with builds or webhook dispatches, or reading another run's dataset, you can reach the full [Apify API](https://docs.apify.com/api/v2) through the client. It provides a dedicated sub-client for each API resource (among them `dataset`, `key_value_store`, `request_queue`, `run`, `actor`, `task`, `schedule`, `webhook`, and `user`), and each operation returns plain Python data structures. ## Actor client @@ -24,20 +24,20 @@ For example, to get the details of your user, you can use this snippet: {ActorClientExample} -You select a resource with the matching method — for example `Actor.apify_client.dataset('')` for a dataset or `Actor.apify_client.run('')` for an Actor run — and then call the operation you need on the returned sub-client. +You select a resource with the matching method (for example, `Actor.apify_client.dataset('')` for a dataset or `Actor.apify_client.run('')` for an Actor run), and then call the operation you need on the returned sub-client. ## Actor new client -If you want to create a completely new instance of the client — for example, to use a different user's token or change the client configuration — you can use the `Actor.new_client` method. It accepts an optional `token` and `api_url`, along with retry and timeout settings (`max_retries`, `min_delay_between_retries`, `timeout`), and returns a fresh `ApifyClientAsync`: +If you want to create a completely new instance of the client (for example, to use a different user's token or change the client configuration), you can use the `Actor.new_client` method. It accepts an optional `token` and `api_url`, along with retry and timeout settings (`max_retries`, `min_delay_between_retries`, `timeout`), and returns a fresh `ApifyClientAsync`: {ActorNewClientExample} -This is useful when the Actor's own token is not the right one — for instance, when acting on behalf of another user — or when you want different retry and timeout behavior than the shared `Actor.apify_client` instance. +This is useful when the Actor's own token is not the right one, for instance when acting on behalf of another user, or when you want different retry and timeout behavior than the shared `Actor.apify_client` instance. ## Conclusion -This page has shown how to reach the Apify API directly — through the built-in client exposed by `Actor.apify_client`, or a freshly configured one created with `Actor.new_client` — for platform features the SDK does not wrap directly. +This page has shown how to reach the Apify API directly for platform features the SDK does not wrap. You can use the built-in client exposed by `Actor.apify_client`, or a freshly configured one created with `Actor.new_client`. For the full API client documentation, see the [Apify API Client for Python](https://docs.apify.com/api/client/python). diff --git a/docs/02_concepts/09_logging.mdx b/docs/02_concepts/09_logging.mdx index 5530656d2..7aa6c859d 100644 --- a/docs/02_concepts/09_logging.mdx +++ b/docs/02_concepts/09_logging.mdx @@ -20,7 +20,7 @@ When you create an Actor from an Apify-provided template, either in Apify Consol ## Manual configuration -If you are not using an Apify template — or you want to override what it sets up — you can configure the log level and the log formatting yourself. +If you are not using an Apify template, or you want to override what it sets up, you can configure the log level and the log formatting yourself. ### Configuring the log level @@ -119,4 +119,4 @@ You can further decide whether you want to redirect just new logs of the ongoing ## Conclusion -This page has covered how the SDK logs through the `apify` logger — setting the log level, formatting output with `ActorLogFormatter`, using the logger at each level, and redirecting logs from other Actor runs back into the parent run. For more on the underlying logging machinery, see Python's standard [`logging`](https://docs.python.org/3/library/logging.html) module documentation. +This page has covered how the SDK logs through the `apify` logger: setting the log level, formatting output with `ActorLogFormatter`, using the logger at each level, and redirecting logs from other Actor runs back into the parent run. For more on the underlying logging machinery, see Python's standard [`logging`](https://docs.python.org/3/library/logging.html) module documentation. diff --git a/docs/02_concepts/10_configuration.mdx b/docs/02_concepts/10_configuration.mdx index 16c3321a1..a90410d82 100644 --- a/docs/02_concepts/10_configuration.mdx +++ b/docs/02_concepts/10_configuration.mdx @@ -27,7 +27,7 @@ This will cause the Actor to persist its state every 10 seconds: ## Configuring via environment variables -All configuration options can also be set via environment variables. Most options are read from an environment variable named after the option in uppercase; many options accept several aliases — commonly with an `APIFY_`, `ACTOR_`, or `CRAWLEE_` prefix. See the `Configuration` API reference for the full list of configuration options. +All configuration options can also be set via environment variables. Most options are read from an environment variable named after the option in uppercase; many options accept several aliases, commonly with an `APIFY_`, `ACTOR_`, or `CRAWLEE_` prefix. See the `Configuration` API reference for the full list of configuration options. For example, this Actor run will keep the contents of its local storages instead of purging them on start: @@ -48,7 +48,7 @@ The table below lists a few options you are most likely to set yourself. When ru | `log_level` | `APIFY_LOG_LEVEL` | `'INFO'` | Minimum severity of log messages that are printed. | | `headless` | `APIFY_HEADLESS` | `True` | Whether to run browsers in headless mode. | | `storage_dir` | `APIFY_LOCAL_STORAGE_DIR` | `'./storage'` | Directory holding local storages when running outside the platform. | -| `is_at_home` | `APIFY_IS_AT_HOME` | `False` | Set by the platform — `True` when the Actor runs on Apify. | +| `is_at_home` | `APIFY_IS_AT_HOME` | `False` | Set by the platform. `True` when the Actor runs on Apify. | ## Reading the runtime environment diff --git a/docs/02_concepts/11_pay_per_event.mdx b/docs/02_concepts/11_pay_per_event.mdx index bf825ae40..9d61af7c3 100644 --- a/docs/02_concepts/11_pay_per_event.mdx +++ b/docs/02_concepts/11_pay_per_event.mdx @@ -79,6 +79,6 @@ Because pricing configuration is stored by the Apify platform, all events will h ## Conclusion -This page has covered the pay-per-event pricing model — charging for events with `Actor.charge`, respecting the charge limit so your Actor stops once the budget is exhausted, querying the `ChargingManager`, handling the transition from another pricing model, and testing charging locally. +This page has covered the pay-per-event pricing model: charging for events with `Actor.charge`, respecting the charge limit so your Actor stops once the budget is exhausted, querying the `ChargingManager`, handling the transition from another pricing model, and testing charging locally. For comprehensive details on pay-per-event pricing and Actor monetization, see the [pay-per-event](https://docs.apify.com/platform/actors/publishing/monetize/pay-per-event) and [monetization](https://docs.apify.com/platform/actors/publishing/monetize) documentation on the Apify platform. diff --git a/docs/02_concepts/12_storage_clients.mdx b/docs/02_concepts/12_storage_clients.mdx index f4ea5a876..5437e16b6 100644 --- a/docs/02_concepts/12_storage_clients.mdx +++ b/docs/02_concepts/12_storage_clients.mdx @@ -10,14 +10,14 @@ import ApiLink from '@theme/ApiLink'; import SharedRequestQueueExample from '!!raw-loader!roa-loader!./code/12_shared_request_queue.py'; import CustomStorageClientExample from '!!raw-loader!roa-loader!./code/12_custom_storage_client.py'; -Storage clients are the components that actually read and write your [storages](./storages) — datasets, key-value stores, and request queues. The Apify SDK selects an appropriate client automatically based on where the Actor runs, so for most Actors you never need to think about them. This page explains the available clients and how to customize them when you do. +Storage clients are the components that actually read and write your [storages](./storages): datasets, key-value stores, and request queues. The Apify SDK selects an appropriate client automatically based on where the Actor runs, so for most Actors you never need to think about them. This page explains the available clients and how to customize them when you do. ## How the Actor selects a storage client -By default, the Actor uses a `SmartApifyStorageClient` — a hybrid client that delegates to one of two underlying clients depending on the environment: +By default, the Actor uses a `SmartApifyStorageClient`, a hybrid client that delegates to one of two underlying clients depending on the environment: -- When running **on the Apify platform** (detected automatically), or when you pass `force_cloud=True`, it uses the **cloud** client — `ApifyStorageClient`, which persists data through the Apify API. -- When running **locally**, it uses the **local** client — `FileSystemStorageClient`, which emulates platform storages on your filesystem under the `storage` folder. +- When running **on the Apify platform** (detected automatically), or when you pass `force_cloud=True`, it uses the **cloud** client, `ApifyStorageClient`, which persists data through the Apify API. +- When running **locally**, it uses the **local** client, `FileSystemStorageClient`, which emulates platform storages on your filesystem under the `storage` folder. This is what lets the same Actor code run unchanged both locally and on the platform. @@ -30,9 +30,9 @@ The `apify.storage_clients` module provides the following clients: - `FileSystemStorageClient` — persists data to the local filesystem. Used as the default local client. - `MemoryStorageClient` — keeps everything in memory only; nothing is persisted. Useful for tests and short-lived runs. -All of these implement Crawlee's `StorageClient` interface, so any of them can be used as a sub-client of `SmartApifyStorageClient` — see [customizing the storage client](#customizing-the-storage-client) below. +All of these implement Crawlee's `StorageClient` interface, so any of them can be used as a sub-client of `SmartApifyStorageClient`. See [customizing the storage client](#customizing-the-storage-client) below. -Crawlee additionally ships storage clients backed by a self-hosted database — a [`RedisStorageClient`](https://crawlee.dev/python/api/class/RedisStorageClient) and a [`SqlStorageClient`](https://crawlee.dev/python/api/class/SqlStorageClient). The Apify SDK does not re-export these, because they each require an extra dependency that the SDK does not install. To use one, install the matching Crawlee extra (for example `pip install 'crawlee[redis]'` or `crawlee[sql-postgres]` / `crawlee[sql-sqlite]`), import the client from `crawlee.storage_clients`, and pass it as a sub-client of `SmartApifyStorageClient`. See the [Crawlee storage clients guide](https://crawlee.dev/python/docs/guides/storage-clients) for details. +Crawlee additionally ships storage clients backed by a self-hosted database: a [`RedisStorageClient`](https://crawlee.dev/python/api/class/RedisStorageClient) and a [`SqlStorageClient`](https://crawlee.dev/python/api/class/SqlStorageClient). The Apify SDK does not re-export these, because they each require an extra dependency that the SDK does not install. To use one, install the matching Crawlee extra (for example `pip install 'crawlee[redis]'` or `crawlee[sql-postgres]` / `crawlee[sql-sqlite]`), import the client from `crawlee.storage_clients`, and pass it as a sub-client of `SmartApifyStorageClient`. See the [Crawlee storage clients guide](https://crawlee.dev/python/docs/guides/storage-clients) for details. ## Single vs. shared request queue @@ -49,11 +49,11 @@ To opt into the shared client, set it as the cloud client of the `SmartApifyStor ## Using cloud storage while running locally -When developing locally, storages are read from and written to the local filesystem by default. To work with a storage on the Apify platform instead — for example, to read the output of a remote Actor run — pass `force_cloud=True` to `Actor.open_dataset`, `Actor.open_key_value_store`, or `Actor.open_request_queue`. This requires an Apify token, provided via the `APIFY_TOKEN` environment variable. +When developing locally, storages are read from and written to the local filesystem by default. To work with a storage on the Apify platform instead (for example, to read the output of a remote Actor run), pass `force_cloud=True` to `Actor.open_dataset`, `Actor.open_key_value_store`, or `Actor.open_request_queue`. This requires an Apify token, provided via the `APIFY_TOKEN` environment variable. ## Customizing the storage client -You can replace either of the underlying clients — for example, to keep all local data in memory instead of on disk. To do this, set a `SmartApifyStorageClient` with your chosen sub-clients in the service locator **before** entering the Actor context (or awaiting `Actor.init`): +You can replace either of the underlying clients, for example to keep all local data in memory instead of on disk. To do this, set a `SmartApifyStorageClient` with your chosen sub-clients in the service locator **before** entering the Actor context (or awaiting `Actor.init`): {CustomStorageClientExample} @@ -61,7 +61,7 @@ You can replace either of the underlying clients — for example, to keep all lo :::note -The Actor's storage client must be a `SmartApifyStorageClient`. Setting a bare `ApifyStorageClient` or `MemoryStorageClient` directly in the service locator raises an error — wrap it in a `SmartApifyStorageClient` as shown above. +The Actor's storage client must be a `SmartApifyStorageClient`. Setting a bare `ApifyStorageClient` or `MemoryStorageClient` directly in the service locator raises an error. Wrap it in a `SmartApifyStorageClient` as shown above. ::: From b6834ba9db01bf809a6dc3b124808b28b4aec4ae Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Tue, 9 Jun 2026 10:49:32 +0200 Subject: [PATCH 03/10] docs: adjust wording style --- docs/01_introduction/index.mdx | 4 ++-- docs/02_concepts/08_access_apify_api.mdx | 4 ++-- docs/02_concepts/12_storage_clients.mdx | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/01_introduction/index.mdx b/docs/01_introduction/index.mdx index a46df46e0..d0d376844 100644 --- a/docs/01_introduction/index.mdx +++ b/docs/01_introduction/index.mdx @@ -13,12 +13,12 @@ The Apify SDK for Python is the official library for creating [Apify Actors](htt - **Actor lifecycle management** — initialization, graceful shutdown, status messages, rebooting, and metamorphing. - **Storage access** — datasets, key-value stores, and request queues, with automatic local emulation when running outside the platform. -- **Actor input** — convenient access to the Actor input, including automatic decryption of secret fields. +- **Actor input** — access to the Actor input, including automatic decryption of secret fields. - **Events & state persistence** — react to platform events (system info, migration, abort) and persist state across migrations and restarts. - **Proxy management** — Apify Proxy and custom proxies, with session and tiered-proxy support. - **Platform interaction** — start, call, and abort other Actors and tasks, create webhooks, and reach the full Apify API client. - **Monetization** — charge users with the pay-per-event pricing model. -- **Framework integrations** — first-class support for [Crawlee](../guides/crawlee) and [Scrapy](../guides/scrapy), with guides for [Playwright](../guides/playwright) and others. +- **Framework integrations** — support for [Crawlee](../guides/crawlee) and [Scrapy](../guides/scrapy), with guides for [Playwright](../guides/playwright) and others. {IntroductionExample} diff --git a/docs/02_concepts/08_access_apify_api.mdx b/docs/02_concepts/08_access_apify_api.mdx index a06a0ad73..4d8dacfdd 100644 --- a/docs/02_concepts/08_access_apify_api.mdx +++ b/docs/02_concepts/08_access_apify_api.mdx @@ -12,11 +12,11 @@ import ActorNewClientExample from '!!raw-loader!roa-loader!./code/08_actor_new_c The Apify SDK provides a built-in instance of the [Apify API Client](https://docs.apify.com/api/client/python) for accessing Apify platform features beyond what the SDK covers directly. -The SDK wraps the most common operations (opening storages, reading input, charging, and starting other Actors) in convenient high-level methods. When you need something it does not expose directly, such as managing schedules, listing your Actors and runs, working with builds or webhook dispatches, or reading another run's dataset, you can reach the full [Apify API](https://docs.apify.com/api/v2) through the client. It provides a dedicated sub-client for each API resource (among them `dataset`, `key_value_store`, `request_queue`, `run`, `actor`, `task`, `schedule`, `webhook`, and `user`), and each operation returns plain Python data structures. +The SDK wraps the most common operations (opening storages, reading input, charging, and starting other Actors) in high-level methods. When you need something it does not expose directly, such as managing schedules, listing your Actors and runs, working with builds or webhook dispatches, or reading another run's dataset, you can reach the full [Apify API](https://docs.apify.com/api/v2) through the client. It provides a dedicated sub-client for each API resource (among them `dataset`, `key_value_store`, `request_queue`, `run`, `actor`, `task`, `schedule`, `webhook`, and `user`), and each operation returns plain Python data structures. ## Actor client -To access the provided instance of [`ApifyClientAsync`](https://docs.apify.com/api/client/python/reference/class/ApifyClientAsync), you can use the `Actor.apify_client` property. This instance is already authenticated with the Actor's API token and points at the same API the Actor runs against, so it is ready to use immediately. +To access the provided instance of [`ApifyClientAsync`](https://docs.apify.com/api/client/python/reference/class/ApifyClientAsync), you can use the `Actor.apify_client` property. This instance is already authenticated with the Actor's API token and points at the same API the Actor runs against. It is ready to use immediately. For example, to get the details of your user, you can use this snippet: diff --git a/docs/02_concepts/12_storage_clients.mdx b/docs/02_concepts/12_storage_clients.mdx index 5437e16b6..81d3e8971 100644 --- a/docs/02_concepts/12_storage_clients.mdx +++ b/docs/02_concepts/12_storage_clients.mdx @@ -10,7 +10,7 @@ import ApiLink from '@theme/ApiLink'; import SharedRequestQueueExample from '!!raw-loader!roa-loader!./code/12_shared_request_queue.py'; import CustomStorageClientExample from '!!raw-loader!roa-loader!./code/12_custom_storage_client.py'; -Storage clients are the components that actually read and write your [storages](./storages): datasets, key-value stores, and request queues. The Apify SDK selects an appropriate client automatically based on where the Actor runs, so for most Actors you never need to think about them. This page explains the available clients and how to customize them when you do. +Storage clients are the components that actually read and write your [storages](./storages): datasets, key-value stores, and request queues. The Apify SDK selects an appropriate client automatically based on where the Actor runs. For most Actors you never need to think about them. This page explains the available clients and how to customize them when you do. ## How the Actor selects a storage client @@ -38,7 +38,7 @@ Crawlee additionally ships storage clients backed by a self-hosted database: a [ `ApifyStorageClient` supports two ways of accessing the Apify request queue, selected via its `request_queue_access` argument: -- **`'single'`** (default) — optimized for a single consumer. It makes far fewer API calls, so it is cheaper and faster, but it does not support multiple clients consuming the same queue concurrently. This is the right choice for the majority of Actors. +- **`'single'`** (default) — optimized for a single consumer. It makes fewer API calls, so it is cheaper and faster, but it does not support multiple clients consuming the same queue concurrently. This is the right choice for the majority of Actors. - **`'shared'`** — supports multiple consumers working on the same queue at the same time, at the cost of more API calls. To opt into the shared client, set it as the cloud client of the `SmartApifyStorageClient` in the [service locator](https://crawlee.dev/python/docs/guides/service-locator) before entering the Actor context: From 1f8be5d1f8434839f77ba336c0ce40a56db721aa Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Thu, 11 Jun 2026 14:13:21 +0200 Subject: [PATCH 04/10] docs: Polish wording to match docs writing style --- docs/01_introduction/index.mdx | 20 ++++++++++---------- docs/02_concepts/08_access_apify_api.mdx | 4 ++-- docs/02_concepts/09_logging.mdx | 2 +- docs/02_concepts/10_configuration.mdx | 2 +- docs/02_concepts/11_pay_per_event.mdx | 2 +- docs/02_concepts/12_storage_clients.mdx | 22 +++++++++++----------- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/01_introduction/index.mdx b/docs/01_introduction/index.mdx index d0d376844..26c5705d1 100644 --- a/docs/01_introduction/index.mdx +++ b/docs/01_introduction/index.mdx @@ -9,16 +9,16 @@ import CodeBlock from '@theme/CodeBlock'; import IntroductionExample from '!!raw-loader!./code/01_introduction.py'; -The Apify SDK for Python is the official library for creating [Apify Actors](https://docs.apify.com/platform/actors) in Python. It gives you everything you need to build an Actor and run it both locally and on the [Apify platform](https://docs.apify.com/platform), including: - -- **Actor lifecycle management** — initialization, graceful shutdown, status messages, rebooting, and metamorphing. -- **Storage access** — datasets, key-value stores, and request queues, with automatic local emulation when running outside the platform. -- **Actor input** — access to the Actor input, including automatic decryption of secret fields. -- **Events & state persistence** — react to platform events (system info, migration, abort) and persist state across migrations and restarts. -- **Proxy management** — Apify Proxy and custom proxies, with session and tiered-proxy support. -- **Platform interaction** — start, call, and abort other Actors and tasks, create webhooks, and reach the full Apify API client. -- **Monetization** — charge users with the pay-per-event pricing model. -- **Framework integrations** — support for [Crawlee](../guides/crawlee) and [Scrapy](../guides/scrapy), with guides for [Playwright](../guides/playwright) and others. +The Apify SDK for Python is the official library for creating [Apify Actors](https://docs.apify.com/platform/actors) in Python. It provides everything you need to build an Actor and run it both locally and on the [Apify platform](https://docs.apify.com/platform). With the SDK, you can: + +- Manage the Actor lifecycle: initialization, graceful shutdown, status messages, rebooting, and metamorphing. +- Work with datasets, key-value stores, and request queues, with automatic local emulation when running outside the platform. +- Read the Actor input, including automatic decryption of secret fields. +- React to platform events (system info, migration, abort) and persist state across migrations and restarts. +- Manage proxies, both Apify Proxy and your own, with session and tiered-proxy support. +- Start, call, and abort other Actors and tasks, create webhooks, and reach the full Apify API client. +- Charge users with the pay-per-event pricing model. +- Integrate with [Crawlee](../guides/crawlee) and [Scrapy](../guides/scrapy), with guides for [Playwright](../guides/playwright) and others. {IntroductionExample} diff --git a/docs/02_concepts/08_access_apify_api.mdx b/docs/02_concepts/08_access_apify_api.mdx index 4d8dacfdd..191fdd14d 100644 --- a/docs/02_concepts/08_access_apify_api.mdx +++ b/docs/02_concepts/08_access_apify_api.mdx @@ -12,11 +12,11 @@ import ActorNewClientExample from '!!raw-loader!roa-loader!./code/08_actor_new_c The Apify SDK provides a built-in instance of the [Apify API Client](https://docs.apify.com/api/client/python) for accessing Apify platform features beyond what the SDK covers directly. -The SDK wraps the most common operations (opening storages, reading input, charging, and starting other Actors) in high-level methods. When you need something it does not expose directly, such as managing schedules, listing your Actors and runs, working with builds or webhook dispatches, or reading another run's dataset, you can reach the full [Apify API](https://docs.apify.com/api/v2) through the client. It provides a dedicated sub-client for each API resource (among them `dataset`, `key_value_store`, `request_queue`, `run`, `actor`, `task`, `schedule`, `webhook`, and `user`), and each operation returns plain Python data structures. +The SDK wraps the most common operations (opening storages, reading input, charging, and starting other Actors) in high-level methods. When you need something it does not expose directly, such as managing schedules, listing your Actors and runs, working with builds or webhook dispatches, or reading another run's dataset, you can reach the full [Apify API](https://docs.apify.com/api/v2) through the client. It provides a dedicated sub-client for each API resource (for example `dataset`, `run`, or `schedule`), and each operation returns plain Python data structures. ## Actor client -To access the provided instance of [`ApifyClientAsync`](https://docs.apify.com/api/client/python/reference/class/ApifyClientAsync), you can use the `Actor.apify_client` property. This instance is already authenticated with the Actor's API token and points at the same API the Actor runs against. It is ready to use immediately. +To access the provided instance of [`ApifyClientAsync`](https://docs.apify.com/api/client/python/reference/class/ApifyClientAsync), you can use the `Actor.apify_client` property. This instance is already authenticated with the Actor's API token and points at the same API the Actor runs against. For example, to get the details of your user, you can use this snippet: diff --git a/docs/02_concepts/09_logging.mdx b/docs/02_concepts/09_logging.mdx index 7aa6c859d..7b0962bf9 100644 --- a/docs/02_concepts/09_logging.mdx +++ b/docs/02_concepts/09_logging.mdx @@ -101,7 +101,7 @@ Typical use case for log redirection is to call another Actor using the -Each default redirect logger log entry will have a specific format. After the timestamp, it will contain cyan colored text that will contain the redirect information - the other Actor's name and the run ID. The rest of the log message will be printed in the same manner as the parent Actor's logger is configured. +Each default redirect logger log entry will have a specific format. After the timestamp, it will contain cyan colored text that will contain the redirect information: the other Actor's name and the run ID. The rest of the log message will be printed in the same manner as the parent Actor's logger is configured. The log redirection can be deep, meaning that if the other Actor also starts another Actor and is redirecting logs from it, then in the top-level Actor, you can see it as well. See the following example screenshot of the Apify log console when one Actor recursively starts itself (there are 2 levels of recursion in the example). diff --git a/docs/02_concepts/10_configuration.mdx b/docs/02_concepts/10_configuration.mdx index a90410d82..800cc5ce7 100644 --- a/docs/02_concepts/10_configuration.mdx +++ b/docs/02_concepts/10_configuration.mdx @@ -27,7 +27,7 @@ This will cause the Actor to persist its state every 10 seconds: ## Configuring via environment variables -All configuration options can also be set via environment variables. Most options are read from an environment variable named after the option in uppercase; many options accept several aliases, commonly with an `APIFY_`, `ACTOR_`, or `CRAWLEE_` prefix. See the `Configuration` API reference for the full list of configuration options. +All configuration options can also be set via environment variables. Most options are read from an environment variable named after the option in uppercase. Many options also accept several aliases, commonly with an `APIFY_`, `ACTOR_`, or `CRAWLEE_` prefix. For the full list of configuration options, see the `Configuration` API reference. For example, this Actor run will keep the contents of its local storages instead of purging them on start: diff --git a/docs/02_concepts/11_pay_per_event.mdx b/docs/02_concepts/11_pay_per_event.mdx index 9d61af7c3..b726c2b62 100644 --- a/docs/02_concepts/11_pay_per_event.mdx +++ b/docs/02_concepts/11_pay_per_event.mdx @@ -31,7 +31,7 @@ After monetization is set in the Apify Console, you can add `Actor.get_charging_manager()` to access the `ChargingManager`, which can provide more detailed information - for example how many events of each type can be charged before reaching the configured limit. +If you need finer control over charging, you can call `Actor.get_charging_manager()` to access the `ChargingManager`, which can provide more detailed information, for example how many events of each type can be charged before reaching the configured limit. ### Handling the charge limit diff --git a/docs/02_concepts/12_storage_clients.mdx b/docs/02_concepts/12_storage_clients.mdx index 81d3e8971..ecf4497ac 100644 --- a/docs/02_concepts/12_storage_clients.mdx +++ b/docs/02_concepts/12_storage_clients.mdx @@ -10,14 +10,14 @@ import ApiLink from '@theme/ApiLink'; import SharedRequestQueueExample from '!!raw-loader!roa-loader!./code/12_shared_request_queue.py'; import CustomStorageClientExample from '!!raw-loader!roa-loader!./code/12_custom_storage_client.py'; -Storage clients are the components that actually read and write your [storages](./storages): datasets, key-value stores, and request queues. The Apify SDK selects an appropriate client automatically based on where the Actor runs. For most Actors you never need to think about them. This page explains the available clients and how to customize them when you do. +Storage clients are the components that read and write your [storages](./storages): datasets, key-value stores, and request queues. The Apify SDK selects an appropriate client automatically based on where the Actor runs. For most Actors you never need to think about them. This page explains the available clients and how to customize them when you do. ## How the Actor selects a storage client By default, the Actor uses a `SmartApifyStorageClient`, a hybrid client that delegates to one of two underlying clients depending on the environment: -- When running **on the Apify platform** (detected automatically), or when you pass `force_cloud=True`, it uses the **cloud** client, `ApifyStorageClient`, which persists data through the Apify API. -- When running **locally**, it uses the **local** client, `FileSystemStorageClient`, which emulates platform storages on your filesystem under the `storage` folder. +- When running on the Apify platform (detected automatically), or when you pass `force_cloud=True`, it uses the cloud client, `ApifyStorageClient`, which persists data through the Apify API. +- When running locally, it uses the local client, `FileSystemStorageClient`, which emulates platform storages on your filesystem under the `storage` folder. This is what lets the same Actor code run unchanged both locally and on the platform. @@ -25,21 +25,21 @@ This is what lets the same Actor code run unchanged both locally and on the plat The `apify.storage_clients` module provides the following clients: -- `SmartApifyStorageClient` — the default hybrid client described above. It wraps a `cloud_storage_client` and a `local_storage_client` and routes each call to the right one. -- `ApifyStorageClient` — talks to the Apify API. Used as the cloud client. -- `FileSystemStorageClient` — persists data to the local filesystem. Used as the default local client. -- `MemoryStorageClient` — keeps everything in memory only; nothing is persisted. Useful for tests and short-lived runs. +- `SmartApifyStorageClient` - the default hybrid client described above. It wraps a `cloud_storage_client` and a `local_storage_client` and routes each call to the right one. +- `ApifyStorageClient` - talks to the Apify API. Used as the cloud client. +- `FileSystemStorageClient` - persists data to the local filesystem. Used as the default local client. +- `MemoryStorageClient` - keeps everything in memory and persists nothing. Useful for tests and short-lived runs. All of these implement Crawlee's `StorageClient` interface, so any of them can be used as a sub-client of `SmartApifyStorageClient`. See [customizing the storage client](#customizing-the-storage-client) below. -Crawlee additionally ships storage clients backed by a self-hosted database: a [`RedisStorageClient`](https://crawlee.dev/python/api/class/RedisStorageClient) and a [`SqlStorageClient`](https://crawlee.dev/python/api/class/SqlStorageClient). The Apify SDK does not re-export these, because they each require an extra dependency that the SDK does not install. To use one, install the matching Crawlee extra (for example `pip install 'crawlee[redis]'` or `crawlee[sql-postgres]` / `crawlee[sql-sqlite]`), import the client from `crawlee.storage_clients`, and pass it as a sub-client of `SmartApifyStorageClient`. See the [Crawlee storage clients guide](https://crawlee.dev/python/docs/guides/storage-clients) for details. +Crawlee additionally ships storage clients backed by a self-hosted database: a [`RedisStorageClient`](https://crawlee.dev/python/api/class/RedisStorageClient) and a [`SqlStorageClient`](https://crawlee.dev/python/api/class/SqlStorageClient). The Apify SDK does not re-export these, because they each require an extra dependency that the SDK does not install. To use one, install the matching Crawlee extra (`crawlee[redis]`, `crawlee[sql-postgres]`, or `crawlee[sql-sqlite]`). Then import the client from `crawlee.storage_clients` and pass it as a sub-client of `SmartApifyStorageClient`. For details, see the [Crawlee storage clients guide](https://crawlee.dev/python/docs/guides/storage-clients). ## Single vs. shared request queue `ApifyStorageClient` supports two ways of accessing the Apify request queue, selected via its `request_queue_access` argument: -- **`'single'`** (default) — optimized for a single consumer. It makes fewer API calls, so it is cheaper and faster, but it does not support multiple clients consuming the same queue concurrently. This is the right choice for the majority of Actors. -- **`'shared'`** — supports multiple consumers working on the same queue at the same time, at the cost of more API calls. +- **`'single'`** (default) - optimized for a single consumer. It makes fewer API calls, so it is cheaper and faster, but it does not support multiple clients consuming the same queue concurrently. This is the right choice for the majority of Actors. +- **`'shared'`** - supports multiple consumers working on the same queue at the same time, at the cost of more API calls. To opt into the shared client, set it as the cloud client of the `SmartApifyStorageClient` in the [service locator](https://crawlee.dev/python/docs/guides/service-locator) before entering the Actor context: @@ -53,7 +53,7 @@ When developing locally, storages are read from and written to the local filesys ## Customizing the storage client -You can replace either of the underlying clients, for example to keep all local data in memory instead of on disk. To do this, set a `SmartApifyStorageClient` with your chosen sub-clients in the service locator **before** entering the Actor context (or awaiting `Actor.init`): +You can replace either of the underlying clients, for example to keep all local data in memory instead of on disk. To do this, set a `SmartApifyStorageClient` with your chosen sub-clients in the service locator before entering the Actor context (or awaiting `Actor.init`): {CustomStorageClientExample} From 0d3a6e1435f5a86599529f7dfa57226cb4baeebc Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Thu, 11 Jun 2026 14:30:19 +0200 Subject: [PATCH 05/10] docs: Fix Python version claim in CONTRIBUTING and PyPI Release Notes URL --- CONTRIBUTING.md | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 927d4a344..cbcaa8b21 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ Here you'll find a contributing guide to get started with development. ## Environment -For local development, it is required to have Python 3.10 (or a later version) installed. +For local development, it is required to have Python 3.11 (or a later version) installed. We use [uv](https://docs.astral.sh/uv/) for project management. Install it and set up your IDE accordingly. diff --git a/pyproject.toml b/pyproject.toml index be95eda8d..6ce930bfb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,7 @@ scrapy = ["scrapy>=2.14.0"] "Documentation" = "https://docs.apify.com/sdk/python/docs/overview" "Homepage" = "https://docs.apify.com/sdk/python/" "Issue Tracker" = "https://github.com/apify/apify-sdk-python/issues" -"Release Notes" = "https://docs.apify.com/sdk/python/docs/upgrading/upgrading-to-v2" +"Release Notes" = "https://docs.apify.com/sdk/python/docs/upgrading/upgrading-to-v4" "Source Code" = "https://github.com/apify/apify-sdk-python" [dependency-groups] From e695d5408c81e53c6eaa4ed331a67d2db8e8e329 Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Fri, 12 Jun 2026 14:23:32 +0200 Subject: [PATCH 06/10] docs: Fix v4 upgrade nesting, quick-start template name, httpx proxy arg, and call snippets --- docs/01_introduction/quick-start.mdx | 2 +- docs/02_concepts/05_proxy_management.mdx | 2 +- docs/02_concepts/code/06_interacting_call.py | 10 ++------- .../code/06_interacting_call_task.py | 10 ++------- docs/04_upgrading/upgrading_to_v4.md | 22 +++++++++---------- 5 files changed, 17 insertions(+), 29 deletions(-) diff --git a/docs/01_introduction/quick-start.mdx b/docs/01_introduction/quick-start.mdx index 6557d4781..0df345f49 100644 --- a/docs/01_introduction/quick-start.mdx +++ b/docs/01_introduction/quick-start.mdx @@ -21,7 +21,7 @@ To create and run Actors in Apify Console, refer to the [Console documentation]( To create a new Apify Actor on your computer, you can use the [Apify CLI](/cli), and select one of the [Python Actor templates](https://apify.com/templates?category=python). -For example, to create an Actor from the "[beta] Python SDK" template, you can use the [`apify create` command](/cli/docs/reference#apify-create-actorname). +For example, to create an Actor from the "Getting started with Python" template, you can use the [`apify create` command](/cli/docs/reference#apify-create-actorname). ```bash apify create my-first-actor --template python-start diff --git a/docs/02_concepts/05_proxy_management.mdx b/docs/02_concepts/05_proxy_management.mdx index 32a15d364..c4c56b004 100644 --- a/docs/02_concepts/05_proxy_management.mdx +++ b/docs/02_concepts/05_proxy_management.mdx @@ -110,7 +110,7 @@ You can then use that input to create the proxy configuration: ### HTTPX -To use the generated proxy URLs with the `httpx` library, use the [`proxies`](https://www.python-httpx.org/advanced/#http-proxying) argument: +To use the generated proxy URLs with the `httpx` library, use the [`proxy`](https://www.python-httpx.org/advanced/proxies/) argument: {ProxyHttpxExample} diff --git a/docs/02_concepts/code/06_interacting_call.py b/docs/02_concepts/code/06_interacting_call.py index da798a612..6614abdf2 100644 --- a/docs/02_concepts/code/06_interacting_call.py +++ b/docs/02_concepts/code/06_interacting_call.py @@ -5,7 +5,7 @@ async def main() -> None: async with Actor: - # Start the apify/screenshot-url Actor. + # Start the apify/screenshot-url Actor and wait for it to finish. actor_run = await Actor.call( actor_id='apify/screenshot-url', run_input={ @@ -15,14 +15,8 @@ async def main() -> None: }, ) - if actor_run is None: - raise RuntimeError('Actor task failed to start.') - - # Wait for the Actor run to finish. - run_client = Actor.apify_client.run(actor_run.id) - await run_client.wait_for_finish() - # Get the Actor output from the dataset. + run_client = Actor.apify_client.run(actor_run.id) dataset_client = run_client.dataset() item_list = await dataset_client.list_items() Actor.log.info(f'Actor output: {item_list.items}') diff --git a/docs/02_concepts/code/06_interacting_call_task.py b/docs/02_concepts/code/06_interacting_call_task.py index 4796be4d6..f5b106b69 100644 --- a/docs/02_concepts/code/06_interacting_call_task.py +++ b/docs/02_concepts/code/06_interacting_call_task.py @@ -5,17 +5,11 @@ async def main() -> None: async with Actor: - # Start the Actor task by its ID. + # Start the Actor task by its ID and wait for it to finish. actor_run = await Actor.call_task(task_id='Z3m6FPSj0GYZ25rQc') - if actor_run is None: - raise RuntimeError('Actor task failed to start.') - - # Wait for the task run to finish. + # Get the task run dataset items. run_client = Actor.apify_client.run(actor_run.id) - await run_client.wait_for_finish() - - # Get the task run dataset items dataset_client = run_client.dataset() items = await dataset_client.list_items() Actor.log.info(f'Task run dataset items: {items}') diff --git a/docs/04_upgrading/upgrading_to_v4.md b/docs/04_upgrading/upgrading_to_v4.md index d5be42f31..a7d4ea4ba 100644 --- a/docs/04_upgrading/upgrading_to_v4.md +++ b/docs/04_upgrading/upgrading_to_v4.md @@ -85,11 +85,11 @@ from apify_shared.consts import ApifyEnvVars from apify import ApifyEnvVars ``` -## Typed responses +### Typed responses -`Actor.start`, `Actor.abort`, `Actor.call`, and `Actor.call_task` now return `apify_client._models.Run` instead of the SDK-side `ActorRun`. Both are [Pydantic](https://docs.pydantic.dev/latest/) models with the same snake_case fields, so field access is unchanged — only the type and import path differ. The SDK no longer ships its own response models (`apify._models` has been removed); response shapes come from `apify-client`. +`Actor.start`, `Actor.abort`, `Actor.call`, `Actor.call_task`, and `Actor.set_status_message` now return `apify_client._models.Run` instead of the SDK-side `ActorRun`. Both are [Pydantic](https://docs.pydantic.dev/latest/) models with the same snake_case fields, so field access is unchanged — only the type and import path differ. The SDK no longer ships its own response models (`apify._models` has been removed); response shapes come from `apify-client`. -## Literal string aliases instead of StrEnum classes +### Literal string aliases instead of StrEnum classes Generated enum-like types are now [`Literal`](https://docs.python.org/3/library/typing.html#typing.Literal) string aliases instead of `StrEnum` classes. Pass plain strings instead of enum members. @@ -109,11 +109,11 @@ from apify import Actor, Event Actor.on(Event.SYSTEM_INFO, callback) ``` -## Actor pricing info models +### Actor pricing info models The Actor pricing-info models exposed through `Actor.configuration.actor_pricing_info` — `FreeActorPricingInfo`, `FlatPricePerMonthActorPricingInfo`, `PricePerDatasetItemActorPricingInfo`, `PayPerEventActorPricingInfo`, and the nested `ActorChargeEvent` / `PricingPerEvent` — are now thin subclasses of the corresponding `apify-client` models instead of standalone SDK copies. The discriminated-union shape is unchanged, so existing access (`pricing_model`, per-event titles and prices) keeps working; the models now expose the full `apify-client` field set, and a charge event's `event_price_usd` is optional (it is unset for tier-priced events). `ChargingManager.get_pricing_info()` is unchanged. -## `Webhook` API simplified +### `Webhook` API simplified The `Webhook` model has been slimmed down to only the fields a user sets when defining a webhook. Server-populated response fields (`id`, `created_at`, `modified_at`, `user_id`, `is_ad_hoc`, `condition`, `last_dispatch`, `stats`) and the unused `WebhookCondition` helper class have been removed. The `description` and `should_interpolate_strings` fields have also been removed — they are not part of the ad-hoc webhook representation (`event_types`, `request_url`, `payload_template`, `headers_template`) that `Actor.start` / `Actor.call` / `Actor.call_task` and `Actor.add_webhook` now send. `Webhook` is now a plain `@dataclass` instead of a Pydantic `BaseModel` — construct it with snake_case kwargs; `.model_dump()` / `.model_validate()` are gone. @@ -146,19 +146,19 @@ await Actor.add_webhook( The `idempotency_key` kwarg form on `Actor.add_webhook` still works for one more release but emits a `DeprecationWarning` and will be removed in v5.0. The `ignore_ssl_errors` and `do_not_retry` kwargs have been removed outright — set them on the `Webhook` instance. -`apify.WebhookCondition` is no longer exported; the SDK now binds the webhook to the current Actor run internally. +The SDK now binds the webhook to the current Actor run internally, so there is no webhook condition for you to set. The `webhooks` argument on `Actor.start`, `Actor.call`, and `Actor.call_task` still accepts `list[Webhook]` and the fields used at the call site (`event_types`, `request_url`, `payload_template`, `headers_template`) are unchanged. -## `Actor.new_client` — `timeout` scales all tiers +### `Actor.new_client` — `timeout` scales all tiers `apify-client` v3 split its single timeout into four tiers (short / medium / long / max). `Actor.new_client(timeout=...)` still takes a single `timedelta`; the SDK uses it as the medium-tier baseline and scales the other tiers proportionally (short = `timeout / 6`, long = `timeout * 12`, max = `timeout * 12`). The public signature is unchanged — no migration needed. -## Using the client from `Actor.new_client` +### Using the client from `Actor.new_client` `Actor.new_client()` (and the `Actor.apify_client` property) now returns an `apify-client` v3 `ApifyClientAsync`. When you use that client directly, the client's v3 breaking changes apply — the most impactful ones are below. See the client's [Upgrading to v3](https://docs.apify.com/api/client/python/docs/upgrading/upgrading-to-v3) guide for the complete reference. -### 404 raises `NotFoundError` on ambiguous endpoints +#### 404 raises `NotFoundError` on ambiguous endpoints Direct `.get(id)` and `.delete(id)` calls still swallow 404 into `None`. But where a 404 could mean either the parent or the sub-resource is missing, the client now raises `NotFoundError` instead of returning `None`. @@ -181,7 +181,7 @@ except NotFoundError: dataset = None ``` -### Keyword-only arguments +#### Keyword-only arguments Secondary parameters on several client methods can no longer be passed positionally. @@ -195,7 +195,7 @@ await client.key_value_store('my-store').set_record('my-key', {'data': 1}, conte await client.run('my-run').charge('my-event', count=5) ``` -### Async `iterate_*` are no longer coroutine functions +#### Async `iterate_*` are no longer coroutine functions `DatasetClientAsync.iterate_items()` and `KeyValueStoreClientAsync.iterate_keys()` are now plain `def` functions returning `AsyncIterator[T]`. Consumer code (`async for ...`) is unchanged; if you annotate the call's return value, change `AsyncGenerator[T, None]` to `AsyncIterator[T]`. From cc2daf0c4a0ac134404e36503872ff678b639c86 Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Fri, 12 Jun 2026 14:29:51 +0200 Subject: [PATCH 07/10] docs: Apply review wording suggestions to concept docs --- docs/01_introduction/index.mdx | 2 +- docs/02_concepts/02_actor_input.mdx | 2 +- docs/02_concepts/03_storages.mdx | 2 +- docs/02_concepts/04_actor_events.mdx | 2 +- docs/02_concepts/05_proxy_management.mdx | 2 +- docs/02_concepts/08_access_apify_api.mdx | 4 ++-- docs/02_concepts/09_logging.mdx | 2 +- docs/02_concepts/10_configuration.mdx | 2 +- docs/02_concepts/11_pay_per_event.mdx | 4 ++-- docs/02_concepts/12_storage_clients.mdx | 15 ++++++++++----- 10 files changed, 21 insertions(+), 16 deletions(-) diff --git a/docs/01_introduction/index.mdx b/docs/01_introduction/index.mdx index 26c5705d1..b12ca5bc0 100644 --- a/docs/01_introduction/index.mdx +++ b/docs/01_introduction/index.mdx @@ -16,7 +16,7 @@ The Apify SDK for Python is the official library for creating [Apify Actors](htt - Read the Actor input, including automatic decryption of secret fields. - React to platform events (system info, migration, abort) and persist state across migrations and restarts. - Manage proxies, both Apify Proxy and your own, with session and tiered-proxy support. -- Start, call, and abort other Actors and tasks, create webhooks, and reach the full Apify API client. +- Start, call, and abort Actors and tasks, create webhooks, and reach the full Apify API client. - Charge users with the pay-per-event pricing model. - Integrate with [Crawlee](../guides/crawlee) and [Scrapy](../guides/scrapy), with guides for [Playwright](../guides/playwright) and others. diff --git a/docs/02_concepts/02_actor_input.mdx b/docs/02_concepts/02_actor_input.mdx index a46210af4..3decde235 100644 --- a/docs/02_concepts/02_actor_input.mdx +++ b/docs/02_concepts/02_actor_input.mdx @@ -12,7 +12,7 @@ import ApiLink from '@theme/ApiLink'; The Actor gets its [input](https://docs.apify.com/platform/actors/running/input) from the input record in its default [key-value store](https://docs.apify.com/platform/storage/key-value-store). -To access it, instead of reading the record manually, you can use the `Actor.get_input` convenience method. It will get the input record key from the Actor configuration, read the record from the default key-value store, and decrypt any [secret input fields](https://docs.apify.com/platform/actors/development/secret-input). +To access it, instead of reading the record manually, you can use the `Actor.get_input` convenience method. It gets the input record key from the Actor configuration, reads the record from the default key-value store, and decrypts any [secret input fields](https://docs.apify.com/platform/actors/development/secret-input). For example, if an Actor received a JSON input with two fields, `{ "firstNumber": 1, "secondNumber": 2 }`, this is how you might process it: diff --git a/docs/02_concepts/03_storages.mdx b/docs/02_concepts/03_storages.mdx index 8bbc6eccc..bb616813d 100644 --- a/docs/02_concepts/03_storages.mdx +++ b/docs/02_concepts/03_storages.mdx @@ -183,7 +183,7 @@ To check if all the requests in the queue are handled, you can use the diff --git a/docs/02_concepts/05_proxy_management.mdx b/docs/02_concepts/05_proxy_management.mdx index c4c56b004..24748f01d 100644 --- a/docs/02_concepts/05_proxy_management.mdx +++ b/docs/02_concepts/05_proxy_management.mdx @@ -106,7 +106,7 @@ You can then use that input to create the proxy configuration: ## Using the generated proxy URLs -`ProxyConfiguration` only generates proxy URLs. It does not make requests itself. Pass a generated URL to whichever HTTP client your Actor uses to route requests through the proxy. +`ProxyConfiguration` only generates proxy URLs. It doesn't make requests. To route requests through the proxy, pass a generated URL to the HTTP client your Actor uses. ### HTTPX diff --git a/docs/02_concepts/08_access_apify_api.mdx b/docs/02_concepts/08_access_apify_api.mdx index 191fdd14d..4fee2c6a9 100644 --- a/docs/02_concepts/08_access_apify_api.mdx +++ b/docs/02_concepts/08_access_apify_api.mdx @@ -12,7 +12,7 @@ import ActorNewClientExample from '!!raw-loader!roa-loader!./code/08_actor_new_c The Apify SDK provides a built-in instance of the [Apify API Client](https://docs.apify.com/api/client/python) for accessing Apify platform features beyond what the SDK covers directly. -The SDK wraps the most common operations (opening storages, reading input, charging, and starting other Actors) in high-level methods. When you need something it does not expose directly, such as managing schedules, listing your Actors and runs, working with builds or webhook dispatches, or reading another run's dataset, you can reach the full [Apify API](https://docs.apify.com/api/v2) through the client. It provides a dedicated sub-client for each API resource (for example `dataset`, `run`, or `schedule`), and each operation returns plain Python data structures. +The SDK wraps the most common operations (opening storages, reading input, charging, and starting other Actors) in high-level methods. To do things that it doesn't expose directly, such as managing schedules, listing your Actors and runs, working with builds or webhook dispatches, or reading another run's dataset, you can reach the full [Apify API](https://docs.apify.com/api/v2) through the client. It provides a dedicated sub-client for each API resource (for example `dataset`, `run`, or `schedule`), and each operation returns plain Python data structures. ## Actor client @@ -28,7 +28,7 @@ You select a resource with the matching method (for example, `Actor.apify_client ## Actor new client -If you want to create a completely new instance of the client (for example, to use a different user's token or change the client configuration), you can use the `Actor.new_client` method. It accepts an optional `token` and `api_url`, along with retry and timeout settings (`max_retries`, `min_delay_between_retries`, `timeout`), and returns a fresh `ApifyClientAsync`: +To create a completely new instance of the client (for example, to use a different user's token or change the client configuration), use the `Actor.new_client` method. It accepts an optional `token` and `api_url`, along with retry and timeout settings (`max_retries`, `min_delay_between_retries`, `timeout`), and returns a fresh `ApifyClientAsync`: {ActorNewClientExample} diff --git a/docs/02_concepts/09_logging.mdx b/docs/02_concepts/09_logging.mdx index 7b0962bf9..39fd7cbbe 100644 --- a/docs/02_concepts/09_logging.mdx +++ b/docs/02_concepts/09_logging.mdx @@ -20,7 +20,7 @@ When you create an Actor from an Apify-provided template, either in Apify Consol ## Manual configuration -If you are not using an Apify template, or you want to override what it sets up, you can configure the log level and the log formatting yourself. +If you're not using an Apify template, or you want to override what it sets up, you can configure the log level and the log formatting yourself. ### Configuring the log level diff --git a/docs/02_concepts/10_configuration.mdx b/docs/02_concepts/10_configuration.mdx index 800cc5ce7..96ec8a7ac 100644 --- a/docs/02_concepts/10_configuration.mdx +++ b/docs/02_concepts/10_configuration.mdx @@ -37,7 +37,7 @@ APIFY_PURGE_ON_START=0 apify run ### Commonly used options -The table below lists a few options you are most likely to set yourself. When running on the Apify platform or via the Apify CLI, the platform-related options are populated automatically. +The following table lists a few options you are most likely to set yourself. When running on the Apify platform or via the Apify CLI, the platform-related options are populated automatically. | Option | Environment variable | Default | Description | | --- | --- | --- | --- | diff --git a/docs/02_concepts/11_pay_per_event.mdx b/docs/02_concepts/11_pay_per_event.mdx index b726c2b62..7ebd0a528 100644 --- a/docs/02_concepts/11_pay_per_event.mdx +++ b/docs/02_concepts/11_pay_per_event.mdx @@ -13,7 +13,7 @@ import RunnableCodeBlock from '@site/src/components/RunnableCodeBlock'; Apify provides several [pricing models](https://docs.apify.com/platform/actors/publishing/monetize) for monetizing your Actors. The most recent and most flexible one is [pay-per-event](https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event), which lets you charge your users programmatically directly from your Actor. As the name suggests, you may charge the users each time a specific event occurs, for example a call to an external API or when you return a result. -To use the pay-per-event pricing model, you first need to [set it up](https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event) for your Actor in the Apify Console. After that, you're free to start charging for events. +To use the pay-per-event pricing model, first [set it up](https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event) for your Actor in the Apify Console. After that, you can start charging for events. :::info How pay-per-event pricing works @@ -59,7 +59,7 @@ For budget-aware crawling strategies, the `C ## Transitioning from a different pricing model -When you plan to start using the pay-per-event pricing model for an Actor that is already monetized with a different pricing model, your source code will need to support both pricing models during the transition period enforced by the Apify platform. Arguably the most frequent case is the transition from the pay-per-result model which utilizes the `ACTOR_MAX_PAID_DATASET_ITEMS` environment variable to prevent returning unpaid dataset items. The following is an example how to handle such scenarios. The key part is the `ChargingManager.get_pricing_info()` method which returns information about the current pricing model. +When you plan to start using the pay-per-event pricing model for an Actor that is already monetized with a different pricing model, your source code must support both pricing models during the transition period enforced by the Apify platform. The most frequent case is the transition from the pay-per-result model which utilizes the `ACTOR_MAX_PAID_DATASET_ITEMS` environment variable to prevent returning unpaid dataset items. The following is an example how to handle such scenarios. The key part is the `ChargingManager.get_pricing_info()` method which returns information about the current pricing model. {ConditionalActorChargeSource} diff --git a/docs/02_concepts/12_storage_clients.mdx b/docs/02_concepts/12_storage_clients.mdx index ecf4497ac..221af2a09 100644 --- a/docs/02_concepts/12_storage_clients.mdx +++ b/docs/02_concepts/12_storage_clients.mdx @@ -19,26 +19,31 @@ By default, the Actor uses a `SmartA - When running on the Apify platform (detected automatically), or when you pass `force_cloud=True`, it uses the cloud client, `ApifyStorageClient`, which persists data through the Apify API. - When running locally, it uses the local client, `FileSystemStorageClient`, which emulates platform storages on your filesystem under the `storage` folder. -This is what lets the same Actor code run unchanged both locally and on the platform. +As a result, the same Actor code can run unchanged both locally and on the platform. ## Available storage clients The `apify.storage_clients` module provides the following clients: -- `SmartApifyStorageClient` - the default hybrid client described above. It wraps a `cloud_storage_client` and a `local_storage_client` and routes each call to the right one. +- `SmartApifyStorageClient` - the default hybrid client. It wraps a `cloud_storage_client` and a `local_storage_client` and routes each call to the right one. - `ApifyStorageClient` - talks to the Apify API. Used as the cloud client. - `FileSystemStorageClient` - persists data to the local filesystem. Used as the default local client. - `MemoryStorageClient` - keeps everything in memory and persists nothing. Useful for tests and short-lived runs. -All of these implement Crawlee's `StorageClient` interface, so any of them can be used as a sub-client of `SmartApifyStorageClient`. See [customizing the storage client](#customizing-the-storage-client) below. +All of these clients implement Crawlee's `StorageClient` interface, so any of them can be used as a sub-client of `SmartApifyStorageClient`. For details, see [customizing the storage client](#customizing-the-storage-client). -Crawlee additionally ships storage clients backed by a self-hosted database: a [`RedisStorageClient`](https://crawlee.dev/python/api/class/RedisStorageClient) and a [`SqlStorageClient`](https://crawlee.dev/python/api/class/SqlStorageClient). The Apify SDK does not re-export these, because they each require an extra dependency that the SDK does not install. To use one, install the matching Crawlee extra (`crawlee[redis]`, `crawlee[sql-postgres]`, or `crawlee[sql-sqlite]`). Then import the client from `crawlee.storage_clients` and pass it as a sub-client of `SmartApifyStorageClient`. For details, see the [Crawlee storage clients guide](https://crawlee.dev/python/docs/guides/storage-clients). +Crawlee additionally ships storage clients backed by a self-hosted database: a [`RedisStorageClient`](https://crawlee.dev/python/api/class/RedisStorageClient) and a [`SqlStorageClient`](https://crawlee.dev/python/api/class/SqlStorageClient). The Apify SDK doesn't re-export these, because they each require an extra dependency that the SDK doesn't install. To use one of the storage clients: + +1. Install the matching Crawlee extra (`crawlee[redis]`, `crawlee[sql-postgres]`, or `crawlee[sql-sqlite]`). +1. Import the client from `crawlee.storage_clients` and pass it as a sub-client of `SmartApifyStorageClient`. + +For details, see the [Crawlee storage clients guide](https://crawlee.dev/python/docs/guides/storage-clients). ## Single vs. shared request queue `ApifyStorageClient` supports two ways of accessing the Apify request queue, selected via its `request_queue_access` argument: -- **`'single'`** (default) - optimized for a single consumer. It makes fewer API calls, so it is cheaper and faster, but it does not support multiple clients consuming the same queue concurrently. This is the right choice for the majority of Actors. +- **`'single'`** (default) - optimized for a single consumer. It makes fewer API calls, so it is cheaper and faster, but it doesn't support multiple clients consuming the same queue concurrently. This is the right choice for the majority of Actors. - **`'shared'`** - supports multiple consumers working on the same queue at the same time, at the cost of more API calls. To opt into the shared client, set it as the cloud client of the `SmartApifyStorageClient` in the [service locator](https://crawlee.dev/python/docs/guides/service-locator) before entering the Actor context: From 9ebe56cbeb918f97f3a3fb50b28b329aa8dfbdda Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Fri, 12 Jun 2026 14:44:38 +0200 Subject: [PATCH 08/10] docs: Simplify v4 upgrade guide headings (no backticks, no h4) --- docs/04_upgrading/upgrading_to_v4.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/04_upgrading/upgrading_to_v4.md b/docs/04_upgrading/upgrading_to_v4.md index a7d4ea4ba..67bef7fe4 100644 --- a/docs/04_upgrading/upgrading_to_v4.md +++ b/docs/04_upgrading/upgrading_to_v4.md @@ -69,7 +69,7 @@ The deprecated `latest_sdk_version`, `log_format`, and `standby_port` fields hav - In place of `standby_port`, use `web_server_port`. - `latest_sdk_version` and `log_format` don't have replacement. SDK version checking isn't supported for the Python SDK and the log format should be adjusted in code instead. -## Built on `apify-client` v3 +## Built on apify-client v3 The SDK is now built on [`apify-client`](https://docs.apify.com/api/client/python) v3 and no longer depends on `apify-shared`. The sections below cover the user-visible consequences; see the client's [Upgrading to v3](https://docs.apify.com/api/client/python/docs/upgrading/upgrading-to-v3) guide for the full list of changes in the client itself. @@ -113,7 +113,7 @@ Actor.on(Event.SYSTEM_INFO, callback) The Actor pricing-info models exposed through `Actor.configuration.actor_pricing_info` — `FreeActorPricingInfo`, `FlatPricePerMonthActorPricingInfo`, `PricePerDatasetItemActorPricingInfo`, `PayPerEventActorPricingInfo`, and the nested `ActorChargeEvent` / `PricingPerEvent` — are now thin subclasses of the corresponding `apify-client` models instead of standalone SDK copies. The discriminated-union shape is unchanged, so existing access (`pricing_model`, per-event titles and prices) keeps working; the models now expose the full `apify-client` field set, and a charge event's `event_price_usd` is optional (it is unset for tier-priced events). `ChargingManager.get_pricing_info()` is unchanged. -### `Webhook` API simplified +### Webhook API simplified The `Webhook` model has been slimmed down to only the fields a user sets when defining a webhook. Server-populated response fields (`id`, `created_at`, `modified_at`, `user_id`, `is_ad_hoc`, `condition`, `last_dispatch`, `stats`) and the unused `WebhookCondition` helper class have been removed. The `description` and `should_interpolate_strings` fields have also been removed — they are not part of the ad-hoc webhook representation (`event_types`, `request_url`, `payload_template`, `headers_template`) that `Actor.start` / `Actor.call` / `Actor.call_task` and `Actor.add_webhook` now send. `Webhook` is now a plain `@dataclass` instead of a Pydantic `BaseModel` — construct it with snake_case kwargs; `.model_dump()` / `.model_validate()` are gone. @@ -150,15 +150,15 @@ The SDK now binds the webhook to the current Actor run internally, so there is n The `webhooks` argument on `Actor.start`, `Actor.call`, and `Actor.call_task` still accepts `list[Webhook]` and the fields used at the call site (`event_types`, `request_url`, `payload_template`, `headers_template`) are unchanged. -### `Actor.new_client` — `timeout` scales all tiers +### Actor.new_client — timeout scales all tiers `apify-client` v3 split its single timeout into four tiers (short / medium / long / max). `Actor.new_client(timeout=...)` still takes a single `timedelta`; the SDK uses it as the medium-tier baseline and scales the other tiers proportionally (short = `timeout / 6`, long = `timeout * 12`, max = `timeout * 12`). The public signature is unchanged — no migration needed. -### Using the client from `Actor.new_client` +## Using the client from Actor.new_client `Actor.new_client()` (and the `Actor.apify_client` property) now returns an `apify-client` v3 `ApifyClientAsync`. When you use that client directly, the client's v3 breaking changes apply — the most impactful ones are below. See the client's [Upgrading to v3](https://docs.apify.com/api/client/python/docs/upgrading/upgrading-to-v3) guide for the complete reference. -#### 404 raises `NotFoundError` on ambiguous endpoints +### 404 raises NotFoundError on ambiguous endpoints Direct `.get(id)` and `.delete(id)` calls still swallow 404 into `None`. But where a 404 could mean either the parent or the sub-resource is missing, the client now raises `NotFoundError` instead of returning `None`. @@ -181,7 +181,7 @@ except NotFoundError: dataset = None ``` -#### Keyword-only arguments +### Keyword-only arguments Secondary parameters on several client methods can no longer be passed positionally. @@ -195,7 +195,7 @@ await client.key_value_store('my-store').set_record('my-key', {'data': 1}, conte await client.run('my-run').charge('my-event', count=5) ``` -#### Async `iterate_*` are no longer coroutine functions +### Async iterate_* are no longer coroutine functions `DatasetClientAsync.iterate_items()` and `KeyValueStoreClientAsync.iterate_keys()` are now plain `def` functions returning `AsyncIterator[T]`. Consumer code (`async for ...`) is unchanged; if you annotate the call's return value, change `AsyncGenerator[T, None]` to `AsyncIterator[T]`. @@ -212,7 +212,7 @@ Data written by an older SDK uses the pickle format, which v4 does not load. The - HTTP cache: a legacy entry is treated as a cache miss. Scrapy re-fetches the page and re-stores it as JSON, so the cache heals itself. No action is needed. - Request queue: a request stored by an older SDK cannot be reconstructed, so it is skipped and the failure is logged. This matters only when pre-upgrade requests are still in the queue, for example after a run is migrated or restarted, or when you reuse a named request queue. A fresh run is not affected. -### `meta` and `cb_kwargs` must be JSON-serializable +### meta and cb_kwargs must be JSON-serializable Pickle could store arbitrary Python objects. JSON cannot, so the values in a request's `meta` and `cb_kwargs` are now subject to JSON's type system: From 2f53027fc9d63e83b0cc0773f28ea4166aee4747 Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Fri, 12 Jun 2026 15:00:05 +0200 Subject: [PATCH 09/10] backport changes to v3 --- .../version-3.4/01_introduction/index.mdx | 11 ++++++++++- .../version-3.4/01_introduction/quick-start.mdx | 10 ++++++---- .../02_concepts/01_actor_lifecycle.mdx | 2 +- .../version-3.4/02_concepts/02_actor_input.mdx | 6 +++++- .../version-3.4/02_concepts/03_storages.mdx | 16 ++++++++++------ .../version-3.4/02_concepts/04_actor_events.mdx | 4 ++++ .../02_concepts/05_proxy_management.mdx | 14 ++++++++++---- .../06_interacting_with_other_actors.mdx | 4 ++++ .../version-3.4/02_concepts/07_webhooks.mdx | 4 ++++ .../02_concepts/08_access_apify_api.mdx | 14 ++++++++++++-- .../version-3.4/02_concepts/09_logging.mdx | 12 +++++++++--- .../version-3.4/02_concepts/10_configuration.mdx | 4 ++++ .../version-3.4/02_concepts/11_pay_per_event.mdx | 12 ++++++++---- 13 files changed, 87 insertions(+), 26 deletions(-) diff --git a/website/versioned_docs/version-3.4/01_introduction/index.mdx b/website/versioned_docs/version-3.4/01_introduction/index.mdx index 2e8039799..b8a279b63 100644 --- a/website/versioned_docs/version-3.4/01_introduction/index.mdx +++ b/website/versioned_docs/version-3.4/01_introduction/index.mdx @@ -9,7 +9,16 @@ import CodeBlock from '@theme/CodeBlock'; import IntroductionExample from '!!raw-loader!./code/01_introduction.py'; -The Apify SDK for Python is the official library for creating [Apify Actors](https://docs.apify.com/platform/actors) in Python. It provides useful features like Actor lifecycle management, local storage emulation, and Actor event handling. +The Apify SDK for Python is the official library for creating [Apify Actors](https://docs.apify.com/platform/actors) in Python. It provides everything you need to build an Actor and run it both locally and on the [Apify platform](https://docs.apify.com/platform). With the SDK, you can: + +- Manage the Actor lifecycle: initialization, graceful shutdown, status messages, rebooting, and metamorphing. +- Work with datasets, key-value stores, and request queues, with automatic local emulation when running outside the platform. +- Read the Actor input, including automatic decryption of secret fields. +- React to platform events (system info, migration, abort) and persist state across migrations and restarts. +- Manage proxies, both Apify Proxy and your own, with session and tiered-proxy support. +- Start, call, and abort Actors and tasks, create webhooks, and reach the full Apify API client. +- Charge users with the pay-per-event pricing model. +- Integrate with [Crawlee](../guides/crawlee) and [Scrapy](../guides/scrapy), with guides for [Playwright](../guides/playwright) and others. {IntroductionExample} diff --git a/website/versioned_docs/version-3.4/01_introduction/quick-start.mdx b/website/versioned_docs/version-3.4/01_introduction/quick-start.mdx index a7123d4ca..e44902f2d 100644 --- a/website/versioned_docs/version-3.4/01_introduction/quick-start.mdx +++ b/website/versioned_docs/version-3.4/01_introduction/quick-start.mdx @@ -21,7 +21,7 @@ To create and run Actors in Apify Console, refer to the [Console documentation]( To create a new Apify Actor on your computer, you can use the [Apify CLI](/cli), and select one of the [Python Actor templates](https://apify.com/templates?category=python). -For example, to create an Actor from the "[beta] Python SDK" template, you can use the [`apify create` command](/cli/docs/reference#apify-create-actorname). +For example, to create an Actor from the "Getting started with Python" template, you can use the [`apify create` command](/cli/docs/reference#apify-create-actorname). ```bash apify create my-first-actor --template python-start @@ -59,7 +59,7 @@ The Actor's runtime dependencies are specified in the `requirements.txt` file, w The Actor's source code is in the `src` folder. This folder contains two important files: - `main.py` - which contains the main function of the Actor -- `__main__.py` - which is the entrypoint of the Actor package setting up the Actor [logger](../concepts/logging) and executing the Actor's main function via [`asyncio.run()`](https://docs.python.org/3/library/asyncio-runner.html#asyncio.run). +- `__main__.py` - which is the entrypoint of the Actor package, executing the Actor's main function via [`asyncio.run()`](https://docs.python.org/3/library/asyncio-runner.html#asyncio.run). @@ -67,7 +67,7 @@ The Actor's source code is in the `src` folder. This folder contains two importa {MainExample}
- + {UnderscoreMainExample} @@ -79,13 +79,15 @@ We recommend keeping the entrypoint for the Actor in the `src/__main__.py` file. ## Next steps +Now that you can create and run an Actor locally, explore the rest of the SDK's features and its framework integrations. + ### Concepts To learn more about the features of the Apify SDK and how to use them, check out the Concepts section in the sidebar: - [Actor lifecycle](../concepts/actor-lifecycle) - [Actor input](../concepts/actor-input) -- [Working with storages](../concepts/storages) +- [Storages](../concepts/storages) - [Actor events & state persistence](../concepts/actor-events) - [Proxy management](../concepts/proxy-management) - [Interacting with other Actors](../concepts/interacting-with-other-actors) diff --git a/website/versioned_docs/version-3.4/02_concepts/01_actor_lifecycle.mdx b/website/versioned_docs/version-3.4/02_concepts/01_actor_lifecycle.mdx index 40826305a..b5acda745 100644 --- a/website/versioned_docs/version-3.4/02_concepts/01_actor_lifecycle.mdx +++ b/website/versioned_docs/version-3.4/02_concepts/01_actor_lifecycle.mdx @@ -106,4 +106,4 @@ Update the status only when the user's understanding of progress changes - avoid ## Conclusion -This page has presented the full Actor lifecycle: initialization, execution, error handling, rebooting, shutdown and status messages. You've seen how the SDK supports both context-based and manual control patterns. For deeper dives, explore the reference docs, [guides](https://docs.apify.com/sdk/python/docs/guides/beautifulsoup-httpx), and [platform documentation](https://docs.apify.com/platform). +This page has presented the full Actor lifecycle: initialization, execution, error handling, rebooting, shutdown and status messages. You've seen how the SDK supports both context-based and manual control patterns. For deeper dives, explore the `Actor` API reference, [guides](../guides/beautifulsoup-httpx), and [platform documentation](https://docs.apify.com/platform). diff --git a/website/versioned_docs/version-3.4/02_concepts/02_actor_input.mdx b/website/versioned_docs/version-3.4/02_concepts/02_actor_input.mdx index 15807c05d..3decde235 100644 --- a/website/versioned_docs/version-3.4/02_concepts/02_actor_input.mdx +++ b/website/versioned_docs/version-3.4/02_concepts/02_actor_input.mdx @@ -12,7 +12,7 @@ import ApiLink from '@theme/ApiLink'; The Actor gets its [input](https://docs.apify.com/platform/actors/running/input) from the input record in its default [key-value store](https://docs.apify.com/platform/storage/key-value-store). -To access it, instead of reading the record manually, you can use the `Actor.get_input` convenience method. It will get the input record key from the Actor configuration, read the record from the default key-value store,and decrypt any [secret input fields](https://docs.apify.com/platform/actors/development/secret-input). +To access it, instead of reading the record manually, you can use the `Actor.get_input` convenience method. It gets the input record key from the Actor configuration, reads the record from the default key-value store, and decrypts any [secret input fields](https://docs.apify.com/platform/actors/development/secret-input). For example, if an Actor received a JSON input with two fields, `{ "firstNumber": 1, "secondNumber": 2 }`, this is how you might process it: @@ -34,4 +34,8 @@ The Apify platform supports [secret input fields](https://docs.apify.com/platfor No special handling is needed in your code — when you call `Actor.get_input`, encrypted fields are automatically decrypted using the Actor's private key, which is provided by the platform via environment variables. You receive the plaintext values directly. +## Conclusion + +This page has shown how to read Actor input with `Actor.get_input`, how to load URL sources with `ApifyRequestList`, and how secret input fields are decrypted automatically when you read them. + For more details on Actor input and how to define input schemas, see the [Actor input](https://docs.apify.com/platform/actors/running/input) and [input schema](https://docs.apify.com/platform/actors/development/input-schema) documentation on the Apify platform. diff --git a/website/versioned_docs/version-3.4/02_concepts/03_storages.mdx b/website/versioned_docs/version-3.4/02_concepts/03_storages.mdx index 059682b2b..de8c88cc3 100644 --- a/website/versioned_docs/version-3.4/02_concepts/03_storages.mdx +++ b/website/versioned_docs/version-3.4/02_concepts/03_storages.mdx @@ -1,6 +1,6 @@ --- id: storages -title: Working with storages +title: Storages description: Use datasets, key-value stores, and request queues to persist Actor data. --- @@ -45,11 +45,11 @@ Each dataset item, key-value store record, or request in a request queue is then When developing locally, opening any storage will by default use local storage. To change this behavior and to use remote storage you have to use `force_cloud=True` argument in `Actor.open_dataset`, `Actor.open_request_queue` or `Actor.open_key_value_store`. Proper use of this argument allows you to work with both local and remote storages. -Calling another remote Actor and accessing its default storage is typical use-case for using `force-cloud=True` argument to open remote Actor's storages. +Calling another remote Actor and accessing its default storage is a typical use-case for using `force_cloud=True` argument to open remote Actor's storages. ### Local storage persistence -By default, the storage contents are persisted across multiple Actor runs. To clean up the Actor storages before the running the Actor, use the `--purge` flag of the [`apify run`](https://docs.apify.com/cli/docs/reference#apify-run) command of the Apify CLI. +By default, the storage contents are persisted across multiple Actor runs. To clean up the Actor storages before running the Actor, use the `--purge` flag of the [`apify run`](https://docs.apify.com/cli/docs/reference#apify-run) command of the Apify CLI. ```bash apify run --purge @@ -106,8 +106,8 @@ To get an iterator of the data, you can use the `Dataset.export_to_csv` -or `Dataset.export_to_json` method. +using the `Dataset.export_to` method with the +`content_type` argument set to `'csv'` or `'json'`. {DatasetExportsExample} @@ -183,6 +183,10 @@ To check if all the requests in the queue are handled, you can use the +## Conclusion + +This page has described the events emitted during a run (`SYSTEM_INFO`, `MIGRATING`, `ABORTING`, `PERSIST_STATE`, and `EXIT`): how to handle them with `Actor.on`, and how to persist state automatically with `Actor.use_state`. + For more details on platform events and state persistence, see the [system events](https://docs.apify.com/platform/actors/development/programming-interface/system-events) and [state persistence](https://docs.apify.com/platform/actors/development/state-persistence) documentation on the Apify platform. diff --git a/website/versioned_docs/version-3.4/02_concepts/05_proxy_management.mdx b/website/versioned_docs/version-3.4/02_concepts/05_proxy_management.mdx index d60763b5c..24748f01d 100644 --- a/website/versioned_docs/version-3.4/02_concepts/05_proxy_management.mdx +++ b/website/versioned_docs/version-3.4/02_concepts/05_proxy_management.mdx @@ -22,7 +22,7 @@ The Apify SDK provides built-in proxy management through the {ApifyProxyExample} @@ -38,7 +38,7 @@ If you want to use Apify Proxy locally, make sure that you run your Actors via t All your proxy needs are managed by the `ProxyConfiguration` class. You create an instance using the `Actor.create_proxy_configuration()` method. Then you generate proxy URLs using the `ProxyConfiguration.new_url()` method. -### Apify proxy vs. your own proxies +### Apify Proxy vs. your own proxies The `ProxyConfiguration` class covers both Apify Proxy and custom proxy URLs, so that you can easily switch between proxy providers. However, some features of the class are available only to Apify Proxy users, mainly because Apify Proxy is what one would call a super-proxy. It's not a single proxy server, but an API endpoint that allows connection through millions of different IP addresses. So the class essentially has two modes: Apify Proxy or Your proxy. @@ -54,7 +54,7 @@ When no `session_id` is provided, your custom proxy URLs are rotated round-robin {ProxyRotationExample} -### Apify proxy configuration +### Apify Proxy configuration With Apify Proxy, you can select specific proxy groups to use, or countries to connect from. For even finer control, you can also target a specific subdivision (e.g. a US state) using the `subdivision_code` parameter alongside `country_code`. This allows you to get better proxy performance after some initial research. @@ -106,9 +106,11 @@ You can then use that input to create the proxy configuration: ## Using the generated proxy URLs +`ProxyConfiguration` only generates proxy URLs. It doesn't make requests. To route requests through the proxy, pass a generated URL to the HTTP client your Actor uses. + ### HTTPX -To use the generated proxy URLs with the `httpx` library, use the [`proxies`](https://www.python-httpx.org/advanced/#http-proxying) argument: +To use the generated proxy URLs with the `httpx` library, use the [`proxy`](https://www.python-httpx.org/advanced/proxies/) argument: {ProxyHttpxExample} @@ -120,4 +122,8 @@ Make sure you have the `httpx` library installed: pip install httpx ``` +## Conclusion + +This page has explained how to manage proxies with the `ProxyConfiguration` class: using Apify Proxy or your own servers, keeping sessions sticky across requests, configuring tiered proxy rotation, and feeding proxy settings from Actor input. + For full details on proxy configuration options, see the `ProxyConfiguration` API reference and the [Apify Proxy documentation](https://docs.apify.com/proxy). diff --git a/website/versioned_docs/version-3.4/02_concepts/06_interacting_with_other_actors.mdx b/website/versioned_docs/version-3.4/02_concepts/06_interacting_with_other_actors.mdx index cb28d7cf9..f7b3fd332 100644 --- a/website/versioned_docs/version-3.4/02_concepts/06_interacting_with_other_actors.mdx +++ b/website/versioned_docs/version-3.4/02_concepts/06_interacting_with_other_actors.mdx @@ -63,4 +63,8 @@ When you set `gracefully=True`, the platform sends `ABORTING` and `PERSIST_STATE {InteractingAbortExample} +## Conclusion + +This page has shown how to interact with other Actors from your code: starting a run with `Actor.start`, waiting for it to finish with `Actor.call` or `Actor.call_task`, transforming a run with `Actor.metamorph`, and stopping one with `Actor.abort`. + For the full list of methods for interacting with other Actors, see the `Actor` API reference. For more details on running Actors and Actor tasks on the platform, see the [Actors](https://docs.apify.com/platform/actors) and [Actor tasks](https://docs.apify.com/platform/actors/tasks) documentation. diff --git a/website/versioned_docs/version-3.4/02_concepts/07_webhooks.mdx b/website/versioned_docs/version-3.4/02_concepts/07_webhooks.mdx index 5016d8a8a..44e7dc1e0 100644 --- a/website/versioned_docs/version-3.4/02_concepts/07_webhooks.mdx +++ b/website/versioned_docs/version-3.4/02_concepts/07_webhooks.mdx @@ -32,4 +32,8 @@ To ensure that duplicate ad-hoc webhooks won't get created in a case of Actor re {WebhookPreventingExample} +## Conclusion + +This page has shown how to create ad-hoc webhooks dynamically with `Actor.add_webhook` and how to avoid creating duplicates across Actor restarts using the `idempotency_key` parameter. + For more information about webhooks, including event types and payloads, see the [Apify webhooks documentation](https://docs.apify.com/platform/integrations/webhooks). diff --git a/website/versioned_docs/version-3.4/02_concepts/08_access_apify_api.mdx b/website/versioned_docs/version-3.4/02_concepts/08_access_apify_api.mdx index 5c4ba7ae7..4fee2c6a9 100644 --- a/website/versioned_docs/version-3.4/02_concepts/08_access_apify_api.mdx +++ b/website/versioned_docs/version-3.4/02_concepts/08_access_apify_api.mdx @@ -12,9 +12,11 @@ import ActorNewClientExample from '!!raw-loader!roa-loader!./code/08_actor_new_c The Apify SDK provides a built-in instance of the [Apify API Client](https://docs.apify.com/api/client/python) for accessing Apify platform features beyond what the SDK covers directly. +The SDK wraps the most common operations (opening storages, reading input, charging, and starting other Actors) in high-level methods. To do things that it doesn't expose directly, such as managing schedules, listing your Actors and runs, working with builds or webhook dispatches, or reading another run's dataset, you can reach the full [Apify API](https://docs.apify.com/api/v2) through the client. It provides a dedicated sub-client for each API resource (for example `dataset`, `run`, or `schedule`), and each operation returns plain Python data structures. + ## Actor client -To access the provided instance of [`ApifyClientAsync`](https://docs.apify.com/api/client/python/reference/class/ApifyClientAsync), you can use the `Actor.apify_client` property. +To access the provided instance of [`ApifyClientAsync`](https://docs.apify.com/api/client/python/reference/class/ApifyClientAsync), you can use the `Actor.apify_client` property. This instance is already authenticated with the Actor's API token and points at the same API the Actor runs against. For example, to get the details of your user, you can use this snippet: @@ -22,12 +24,20 @@ For example, to get the details of your user, you can use this snippet: {ActorClientExample} +You select a resource with the matching method (for example, `Actor.apify_client.dataset('')` for a dataset or `Actor.apify_client.run('')` for an Actor run), and then call the operation you need on the returned sub-client. + ## Actor new client -If you want to create a completely new instance of the client, for example, to get a client for a different user or change the configuration of the client, you can use the `Actor.new_client` method: +To create a completely new instance of the client (for example, to use a different user's token or change the client configuration), use the `Actor.new_client` method. It accepts an optional `token` and `api_url`, along with retry and timeout settings (`max_retries`, `min_delay_between_retries`, `timeout`), and returns a fresh `ApifyClientAsync`: {ActorNewClientExample} +This is useful when the Actor's own token is not the right one, for instance when acting on behalf of another user, or when you want different retry and timeout behavior than the shared `Actor.apify_client` instance. + +## Conclusion + +This page has shown how to reach the Apify API directly for platform features the SDK does not wrap. You can use the built-in client exposed by `Actor.apify_client`, or a freshly configured one created with `Actor.new_client`. + For the full API client documentation, see the [Apify API Client for Python](https://docs.apify.com/api/client/python). diff --git a/website/versioned_docs/version-3.4/02_concepts/09_logging.mdx b/website/versioned_docs/version-3.4/02_concepts/09_logging.mdx index b2066053a..39fd7cbbe 100644 --- a/website/versioned_docs/version-3.4/02_concepts/09_logging.mdx +++ b/website/versioned_docs/version-3.4/02_concepts/09_logging.mdx @@ -20,6 +20,8 @@ When you create an Actor from an Apify-provided template, either in Apify Consol ## Manual configuration +If you're not using an Apify template, or you want to override what it sets up, you can configure the log level and the log formatting yourself. + ### Configuring the log level In Python's default behavior, if you don't configure the logger otherwise, only logs with level `WARNING` or higher are printed out to the standard output, without any formatting. To also have logs with `DEBUG` and `INFO` level printed out, you need to call the [`Logger.setLevel`](https://docs.python.org/3/library/logging.html#logging.Logger.setLevel) method on the logger, with the desired minimum level as an argument. @@ -99,11 +101,11 @@ Typical use case for log redirection is to call another Actor using the -Each default redirect logger log entry will have a specific format. After the timestamp, it will contain cyan colored text that will contain the redirect information - the other actor's name and the run ID. The rest of the log message will be printed in the same manner as the parent Actor's logger is configured. +Each default redirect logger log entry will have a specific format. After the timestamp, it will contain cyan colored text that will contain the redirect information: the other Actor's name and the run ID. The rest of the log message will be printed in the same manner as the parent Actor's logger is configured. -The log redirection can be deep, meaning that if the other actor also starts another actor and is redirecting logs from it, then in the top-level Actor, you can see it as well. See the following example screenshot of the Apify log console when one actor recursively starts itself (there are 2 levels of recursion in the example). +The log redirection can be deep, meaning that if the other Actor also starts another Actor and is redirecting logs from it, then in the top-level Actor, you can see it as well. See the following example screenshot of the Apify log console when one Actor recursively starts itself (there are 2 levels of recursion in the example). -![Console with redirected logs](/img/guides/redirected_logs_example.webp 'Example of console with redirected logs from recursively started actor.') +![Console with redirected logs](/img/guides/redirected_logs_example.webp 'Example of console with redirected logs from recursively started Actor.') ### Redirecting logs from already running Actor run @@ -114,3 +116,7 @@ You can further decide whether you want to redirect just new logs of the ongoing {RedirectLogExistingRun} + +## Conclusion + +This page has covered how the SDK logs through the `apify` logger: setting the log level, formatting output with `ActorLogFormatter`, using the logger at each level, and redirecting logs from other Actor runs back into the parent run. For more on the underlying logging machinery, see Python's standard [`logging`](https://docs.python.org/3/library/logging.html) module documentation. diff --git a/website/versioned_docs/version-3.4/02_concepts/10_configuration.mdx b/website/versioned_docs/version-3.4/02_concepts/10_configuration.mdx index 6296b864b..3357770e0 100644 --- a/website/versioned_docs/version-3.4/02_concepts/10_configuration.mdx +++ b/website/versioned_docs/version-3.4/02_concepts/10_configuration.mdx @@ -51,4 +51,8 @@ The `Actor.is_at_home` method ret {PlatformDetectionExample} +## Conclusion + +This page has shown how to configure an Actor through the `Configuration` class or environment variables, which options you are most likely to set yourself, and how to inspect the runtime environment with `Actor.get_env` and `Actor.is_at_home`. + For the full list of configuration options, see the `Configuration` API reference. For a complete list of environment variables available on the platform, see the [environment variables](https://docs.apify.com/platform/actors/development/programming-interface/environment-variables) documentation. diff --git a/website/versioned_docs/version-3.4/02_concepts/11_pay_per_event.mdx b/website/versioned_docs/version-3.4/02_concepts/11_pay_per_event.mdx index d8c04443e..7ebd0a528 100644 --- a/website/versioned_docs/version-3.4/02_concepts/11_pay_per_event.mdx +++ b/website/versioned_docs/version-3.4/02_concepts/11_pay_per_event.mdx @@ -13,7 +13,7 @@ import RunnableCodeBlock from '@site/src/components/RunnableCodeBlock'; Apify provides several [pricing models](https://docs.apify.com/platform/actors/publishing/monetize) for monetizing your Actors. The most recent and most flexible one is [pay-per-event](https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event), which lets you charge your users programmatically directly from your Actor. As the name suggests, you may charge the users each time a specific event occurs, for example a call to an external API or when you return a result. -To use the pay-per-event pricing model, you first need to [set it up](https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event) for your Actor in the Apify console. After that, you're free to start charging for events. +To use the pay-per-event pricing model, first [set it up](https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event) for your Actor in the Apify Console. After that, you can start charging for events. :::info How pay-per-event pricing works @@ -23,7 +23,7 @@ If you want more details about PPE pricing, please refer to our [PPE documentati ## Charging for events -After monetization is set in the Apify console, you can add `Actor.charge` calls to your code and start monetizing! +After monetization is set in the Apify Console, you can add `Actor.charge` calls to your code and start monetizing! {ActorChargeSource} @@ -31,7 +31,7 @@ After monetization is set in the Apify console, you can add `Actor.get_charging_manager()` to access the `ChargingManager`, which can provide more detailed information - for example how many events of each type can be charged before reaching the configured limit. +If you need finer control over charging, you can call `Actor.get_charging_manager()` to access the `ChargingManager`, which can provide more detailed information, for example how many events of each type can be charged before reaching the configured limit. ### Handling the charge limit @@ -59,7 +59,7 @@ For budget-aware crawling strategies, the `C ## Transitioning from a different pricing model -When you plan to start using the pay-per-event pricing model for an Actor that is already monetized with a different pricing model, your source code will need support both pricing models during the transition period enforced by the Apify platform. Arguably the most frequent case is the transition from the pay-per-result model which utilizes the `ACTOR_MAX_PAID_DATASET_ITEMS` environment variable to prevent returning unpaid dataset items. The following is an example how to handle such scenarios. The key part is the `ChargingManager.get_pricing_info()` method which returns information about the current pricing model. +When you plan to start using the pay-per-event pricing model for an Actor that is already monetized with a different pricing model, your source code must support both pricing models during the transition period enforced by the Apify platform. The most frequent case is the transition from the pay-per-result model which utilizes the `ACTOR_MAX_PAID_DATASET_ITEMS` environment variable to prevent returning unpaid dataset items. The following is an example how to handle such scenarios. The key part is the `ChargingManager.get_pricing_info()` method which returns information about the current pricing model. {ConditionalActorChargeSource} @@ -77,4 +77,8 @@ If you also wish to see a log of all the events charged throughout the run, the Because pricing configuration is stored by the Apify platform, all events will have a default price of $1. +## Conclusion + +This page has covered the pay-per-event pricing model: charging for events with `Actor.charge`, respecting the charge limit so your Actor stops once the budget is exhausted, querying the `ChargingManager`, handling the transition from another pricing model, and testing charging locally. + For comprehensive details on pay-per-event pricing and Actor monetization, see the [pay-per-event](https://docs.apify.com/platform/actors/publishing/monetize/pay-per-event) and [monetization](https://docs.apify.com/platform/actors/publishing/monetize) documentation on the Apify platform. From 03deda91a489fc886e5dcd8d3c2e7049045c7cdb Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Fri, 12 Jun 2026 15:33:17 +0200 Subject: [PATCH 10/10] add some missing links --- docs/01_introduction/index.mdx | 2 +- docs/01_introduction/quick-start.mdx | 2 +- docs/02_concepts/01_actor_lifecycle.mdx | 2 +- docs/02_concepts/07_webhooks.mdx | 2 +- docs/02_concepts/09_logging.mdx | 2 +- docs/02_concepts/11_pay_per_event.mdx | 2 +- docs/03_guides/07_running_webserver.mdx | 2 +- website/versioned_docs/version-3.4/01_introduction/index.mdx | 2 +- .../versioned_docs/version-3.4/01_introduction/quick-start.mdx | 2 +- .../version-3.4/02_concepts/01_actor_lifecycle.mdx | 2 +- website/versioned_docs/version-3.4/02_concepts/07_webhooks.mdx | 2 +- website/versioned_docs/version-3.4/02_concepts/09_logging.mdx | 2 +- .../versioned_docs/version-3.4/02_concepts/11_pay_per_event.mdx | 2 +- .../version-3.4/03_guides/07_running_webserver.mdx | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/01_introduction/index.mdx b/docs/01_introduction/index.mdx index b12ca5bc0..be37d6ac0 100644 --- a/docs/01_introduction/index.mdx +++ b/docs/01_introduction/index.mdx @@ -15,7 +15,7 @@ The Apify SDK for Python is the official library for creating [Apify Actors](htt - Work with datasets, key-value stores, and request queues, with automatic local emulation when running outside the platform. - Read the Actor input, including automatic decryption of secret fields. - React to platform events (system info, migration, abort) and persist state across migrations and restarts. -- Manage proxies, both Apify Proxy and your own, with session and tiered-proxy support. +- Manage proxies, both [Apify Proxy](https://docs.apify.com/platform/proxy) and your own, with session and tiered-proxy support. - Start, call, and abort Actors and tasks, create webhooks, and reach the full Apify API client. - Charge users with the pay-per-event pricing model. - Integrate with [Crawlee](../guides/crawlee) and [Scrapy](../guides/scrapy), with guides for [Playwright](../guides/playwright) and others. diff --git a/docs/01_introduction/quick-start.mdx b/docs/01_introduction/quick-start.mdx index 0df345f49..e0c26fd60 100644 --- a/docs/01_introduction/quick-start.mdx +++ b/docs/01_introduction/quick-start.mdx @@ -17,7 +17,7 @@ import UnderscoreMainExample from '!!raw-loader!./code/actor_structure/__main__. ## Step 1: Create Actors -To create and run Actors in Apify Console, refer to the [Console documentation](/platform/actors/development/quick-start/web-ide). +To create and run Actors in [Apify Console](https://docs.apify.com/platform/console), refer to the [Console documentation](/platform/actors/development/quick-start/web-ide). To create a new Apify Actor on your computer, you can use the [Apify CLI](/cli), and select one of the [Python Actor templates](https://apify.com/templates?category=python). diff --git a/docs/02_concepts/01_actor_lifecycle.mdx b/docs/02_concepts/01_actor_lifecycle.mdx index b5acda745..5c1d54351 100644 --- a/docs/02_concepts/01_actor_lifecycle.mdx +++ b/docs/02_concepts/01_actor_lifecycle.mdx @@ -21,7 +21,7 @@ import RebootExample from '!!raw-loader!roa-loader!./code/01_reboot.py'; import StatusMessageExample from '!!raw-loader!roa-loader!./code/01_status_message.py'; -This guide explains how an **Apify Actor** starts, runs, and shuts down, describing the complete Actor lifecycle. For information about the core concepts such as Actors, the Apify Console, storages, and events, check out the [Apify platform documentation](https://docs.apify.com/platform). +This guide explains how an **Apify Actor** starts, runs, and shuts down, describing the complete Actor lifecycle. For information about the core concepts such as Actors, the [Apify Console](https://docs.apify.com/platform/console), storages, and events, check out the [Apify platform documentation](https://docs.apify.com/platform). ## Actor initialization diff --git a/docs/02_concepts/07_webhooks.mdx b/docs/02_concepts/07_webhooks.mdx index 44e7dc1e0..a02dd6a51 100644 --- a/docs/02_concepts/07_webhooks.mdx +++ b/docs/02_concepts/07_webhooks.mdx @@ -16,7 +16,7 @@ You can learn more in the [documentation for webhooks](https://docs.apify.com/pl ## Creating an ad-hoc webhook dynamically -Besides creating webhooks manually in Apify Console, or through the Apify API, you can also create [ad-hoc webhooks](https://docs.apify.com/platform/integrations/webhooks/ad-hoc-webhooks) dynamically from the code of your Actor using the `Actor.add_webhook` method: +Besides creating webhooks manually in [Apify Console](https://docs.apify.com/platform/console), or through the Apify API, you can also create [ad-hoc webhooks](https://docs.apify.com/platform/integrations/webhooks/ad-hoc-webhooks) dynamically from the code of your Actor using the `Actor.add_webhook` method: {WebhookExample} diff --git a/docs/02_concepts/09_logging.mdx b/docs/02_concepts/09_logging.mdx index 39fd7cbbe..cc0b519f1 100644 --- a/docs/02_concepts/09_logging.mdx +++ b/docs/02_concepts/09_logging.mdx @@ -16,7 +16,7 @@ The Apify SDK logs through Python's standard [`logging`](https://docs.python.org ## Automatic configuration -When you create an Actor from an Apify-provided template, either in Apify Console or through the Apify CLI, you do not have to configure the logger yourself. The template already contains initialization code for the logger, which sets the logger level to `DEBUG` and the log formatter to `ActorLogFormatter`. +When you create an Actor from an Apify-provided template, either in [Apify Console](https://docs.apify.com/platform/console) or through the Apify CLI, you do not have to configure the logger yourself. The template already contains initialization code for the logger, which sets the logger level to `DEBUG` and the log formatter to `ActorLogFormatter`. ## Manual configuration diff --git a/docs/02_concepts/11_pay_per_event.mdx b/docs/02_concepts/11_pay_per_event.mdx index 7ebd0a528..5c961460b 100644 --- a/docs/02_concepts/11_pay_per_event.mdx +++ b/docs/02_concepts/11_pay_per_event.mdx @@ -13,7 +13,7 @@ import RunnableCodeBlock from '@site/src/components/RunnableCodeBlock'; Apify provides several [pricing models](https://docs.apify.com/platform/actors/publishing/monetize) for monetizing your Actors. The most recent and most flexible one is [pay-per-event](https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event), which lets you charge your users programmatically directly from your Actor. As the name suggests, you may charge the users each time a specific event occurs, for example a call to an external API or when you return a result. -To use the pay-per-event pricing model, first [set it up](https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event) for your Actor in the Apify Console. After that, you can start charging for events. +To use the pay-per-event pricing model, first [set it up](https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event) for your Actor in the [Apify Console](https://docs.apify.com/platform/console). After that, you can start charging for events. :::info How pay-per-event pricing works diff --git a/docs/03_guides/07_running_webserver.mdx b/docs/03_guides/07_running_webserver.mdx index c17c313be..83d744ce7 100644 --- a/docs/03_guides/07_running_webserver.mdx +++ b/docs/03_guides/07_running_webserver.mdx @@ -16,7 +16,7 @@ Each Actor run on the Apify platform is assigned a unique hard-to-guess URL (for The URL is available in the following places: -- In Apify Console, on the Actor run details page as the **Container URL** field. +- In [Apify Console](https://docs.apify.com/platform/console), on the Actor run details page as the **Container URL** field. - In the API as the `container_url` property of the [Run object](https://docs.apify.com/api/v2#/reference/actors/run-object/get-run). - In the Actor as the `Actor.configuration.container_url` property. diff --git a/website/versioned_docs/version-3.4/01_introduction/index.mdx b/website/versioned_docs/version-3.4/01_introduction/index.mdx index b8a279b63..f0675fe87 100644 --- a/website/versioned_docs/version-3.4/01_introduction/index.mdx +++ b/website/versioned_docs/version-3.4/01_introduction/index.mdx @@ -15,7 +15,7 @@ The Apify SDK for Python is the official library for creating [Apify Actors](htt - Work with datasets, key-value stores, and request queues, with automatic local emulation when running outside the platform. - Read the Actor input, including automatic decryption of secret fields. - React to platform events (system info, migration, abort) and persist state across migrations and restarts. -- Manage proxies, both Apify Proxy and your own, with session and tiered-proxy support. +- Manage proxies, both [Apify Proxy](https://docs.apify.com/platform/proxy) and your own, with session and tiered-proxy support. - Start, call, and abort Actors and tasks, create webhooks, and reach the full Apify API client. - Charge users with the pay-per-event pricing model. - Integrate with [Crawlee](../guides/crawlee) and [Scrapy](../guides/scrapy), with guides for [Playwright](../guides/playwright) and others. diff --git a/website/versioned_docs/version-3.4/01_introduction/quick-start.mdx b/website/versioned_docs/version-3.4/01_introduction/quick-start.mdx index e44902f2d..011067a72 100644 --- a/website/versioned_docs/version-3.4/01_introduction/quick-start.mdx +++ b/website/versioned_docs/version-3.4/01_introduction/quick-start.mdx @@ -17,7 +17,7 @@ import UnderscoreMainExample from '!!raw-loader!./code/actor_structure/__main__. ## Step 1: Create Actors -To create and run Actors in Apify Console, refer to the [Console documentation](/platform/actors/development/quick-start/web-ide). +To create and run Actors in [Apify Console](https://docs.apify.com/platform/console), refer to the [Console documentation](/platform/actors/development/quick-start/web-ide). To create a new Apify Actor on your computer, you can use the [Apify CLI](/cli), and select one of the [Python Actor templates](https://apify.com/templates?category=python). diff --git a/website/versioned_docs/version-3.4/02_concepts/01_actor_lifecycle.mdx b/website/versioned_docs/version-3.4/02_concepts/01_actor_lifecycle.mdx index b5acda745..5c1d54351 100644 --- a/website/versioned_docs/version-3.4/02_concepts/01_actor_lifecycle.mdx +++ b/website/versioned_docs/version-3.4/02_concepts/01_actor_lifecycle.mdx @@ -21,7 +21,7 @@ import RebootExample from '!!raw-loader!roa-loader!./code/01_reboot.py'; import StatusMessageExample from '!!raw-loader!roa-loader!./code/01_status_message.py'; -This guide explains how an **Apify Actor** starts, runs, and shuts down, describing the complete Actor lifecycle. For information about the core concepts such as Actors, the Apify Console, storages, and events, check out the [Apify platform documentation](https://docs.apify.com/platform). +This guide explains how an **Apify Actor** starts, runs, and shuts down, describing the complete Actor lifecycle. For information about the core concepts such as Actors, the [Apify Console](https://docs.apify.com/platform/console), storages, and events, check out the [Apify platform documentation](https://docs.apify.com/platform). ## Actor initialization diff --git a/website/versioned_docs/version-3.4/02_concepts/07_webhooks.mdx b/website/versioned_docs/version-3.4/02_concepts/07_webhooks.mdx index 44e7dc1e0..a02dd6a51 100644 --- a/website/versioned_docs/version-3.4/02_concepts/07_webhooks.mdx +++ b/website/versioned_docs/version-3.4/02_concepts/07_webhooks.mdx @@ -16,7 +16,7 @@ You can learn more in the [documentation for webhooks](https://docs.apify.com/pl ## Creating an ad-hoc webhook dynamically -Besides creating webhooks manually in Apify Console, or through the Apify API, you can also create [ad-hoc webhooks](https://docs.apify.com/platform/integrations/webhooks/ad-hoc-webhooks) dynamically from the code of your Actor using the `Actor.add_webhook` method: +Besides creating webhooks manually in [Apify Console](https://docs.apify.com/platform/console), or through the Apify API, you can also create [ad-hoc webhooks](https://docs.apify.com/platform/integrations/webhooks/ad-hoc-webhooks) dynamically from the code of your Actor using the `Actor.add_webhook` method: {WebhookExample} diff --git a/website/versioned_docs/version-3.4/02_concepts/09_logging.mdx b/website/versioned_docs/version-3.4/02_concepts/09_logging.mdx index 39fd7cbbe..cc0b519f1 100644 --- a/website/versioned_docs/version-3.4/02_concepts/09_logging.mdx +++ b/website/versioned_docs/version-3.4/02_concepts/09_logging.mdx @@ -16,7 +16,7 @@ The Apify SDK logs through Python's standard [`logging`](https://docs.python.org ## Automatic configuration -When you create an Actor from an Apify-provided template, either in Apify Console or through the Apify CLI, you do not have to configure the logger yourself. The template already contains initialization code for the logger, which sets the logger level to `DEBUG` and the log formatter to `ActorLogFormatter`. +When you create an Actor from an Apify-provided template, either in [Apify Console](https://docs.apify.com/platform/console) or through the Apify CLI, you do not have to configure the logger yourself. The template already contains initialization code for the logger, which sets the logger level to `DEBUG` and the log formatter to `ActorLogFormatter`. ## Manual configuration diff --git a/website/versioned_docs/version-3.4/02_concepts/11_pay_per_event.mdx b/website/versioned_docs/version-3.4/02_concepts/11_pay_per_event.mdx index 7ebd0a528..5c961460b 100644 --- a/website/versioned_docs/version-3.4/02_concepts/11_pay_per_event.mdx +++ b/website/versioned_docs/version-3.4/02_concepts/11_pay_per_event.mdx @@ -13,7 +13,7 @@ import RunnableCodeBlock from '@site/src/components/RunnableCodeBlock'; Apify provides several [pricing models](https://docs.apify.com/platform/actors/publishing/monetize) for monetizing your Actors. The most recent and most flexible one is [pay-per-event](https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event), which lets you charge your users programmatically directly from your Actor. As the name suggests, you may charge the users each time a specific event occurs, for example a call to an external API or when you return a result. -To use the pay-per-event pricing model, first [set it up](https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event) for your Actor in the Apify Console. After that, you can start charging for events. +To use the pay-per-event pricing model, first [set it up](https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event) for your Actor in the [Apify Console](https://docs.apify.com/platform/console). After that, you can start charging for events. :::info How pay-per-event pricing works diff --git a/website/versioned_docs/version-3.4/03_guides/07_running_webserver.mdx b/website/versioned_docs/version-3.4/03_guides/07_running_webserver.mdx index c17c313be..83d744ce7 100644 --- a/website/versioned_docs/version-3.4/03_guides/07_running_webserver.mdx +++ b/website/versioned_docs/version-3.4/03_guides/07_running_webserver.mdx @@ -16,7 +16,7 @@ Each Actor run on the Apify platform is assigned a unique hard-to-guess URL (for The URL is available in the following places: -- In Apify Console, on the Actor run details page as the **Container URL** field. +- In [Apify Console](https://docs.apify.com/platform/console), on the Actor run details page as the **Container URL** field. - In the API as the `container_url` property of the [Run object](https://docs.apify.com/api/v2#/reference/actors/run-object/get-run). - In the Actor as the `Actor.configuration.container_url` property.