---
title: "Python SDK · Scrape.ly Docs"
description: "Build Python Actors with the SDK preinstalled in Scrape.ly images."
url: https://scrape.ly/docs/sdk-python
markdown: https://scrape.ly/docs/sdk-python.md
---

# Python SDK

> Build Python Actors with the SDK preinstalled in Scrape.ly images.

The Python SDK is the runtime library for Python Actors on Scrape.ly. It gives you the `Actor` lifecycle API, input and storage access, platform events, Actor-to-Actor calls, webhooks, pay-per-event charging, the platform proxy and the opt-in [Scrape.ly browser](https://scrape.ly/docs/browser.md). It is built on [Crawlee for Python](https://crawlee.dev/python), and its API mirrors the Apify Python SDK, so most Apify Actors run with few or no changes.

The source code is on GitHub: [scrapely-app/scrapely-python](https://github.com/scrapely-app/scrapely-python).

## Getting the SDK

You don't install the SDK for platform runs. It comes preinstalled in the Scrape.ly Python base images, and every Python build on Scrape.ly runs on one of those images. The SDK is published on PyPI as `scrapely-python` and imported as `scrapely`.

> [!CAUTION]
> The PyPI distribution named `scrapely` belongs to an unrelated HTML-scraping library. Never run `pip install scrapely`, and never list it in `requirements.txt`. Doing so installs the wrong package, and the build may fail.

The base images put the SDK in `/opt/scrapely/site-packages`, outside your virtual environment. They add that directory to `PYTHONPATH` and set `SCRAPELY_IS_AT_HOME=1`. The standalone API client, `scrapely-client-python` (import name `scrapely_client`), is preinstalled the same way.

You get the SDK in one of these three ways:

| Your project | What the build does |
| --- | --- |
| No Dockerfile | Generates one from `scrapely/actor-python:3.12`, installs `requirements.txt`, and runs `python /actor/main.py`. |
| Dockerfile `FROM scrapely/actor-python*` | Uses your image and checks that `import scrapely` works. |
| Dockerfile `FROM apify/actor-python*` | Swaps the base for the matching `scrapely/actor-python*` image. If no image matches, it installs the SDK at build time. |

Every Python build also runs a final step. That step uninstalls `apify`, pins `crawlee>=1.8,<2`, reinstalls the SDK's own dependencies and runs `pip check`. Any conflicts `pip check` reports are logged as warnings and don't fail the build. So if your `requirements.txt` pulls in an incompatible Crawlee or the `apify` package, the build corrects it.

### Base images

Each image family below is available for Python 3.11, 3.12, 3.13 and 3.14. Tags look like `scrapely/actor-python-playwright:3.14-latest`. At build time, the platform rewrites the part after the Python version to the SDK release it currently ships.

| Image | Contents |
| --- | --- |
| `scrapely/actor-python` | Python and the SDK |
| `scrapely/actor-python-playwright` | Plus Playwright with all browsers |
| `scrapely/actor-python-playwright-chrome` | Plus Playwright with Chrome |
| `scrapely/actor-python-playwright-firefox` | Plus Playwright with Firefox |
| `scrapely/actor-python-playwright-webkit` | Plus Playwright with WebKit |
| `scrapely/actor-python-playwright-camoufox` | Plus Playwright with Camoufox |
| `scrapely/actor-python-selenium` | Plus Selenium |

The SDK requires Python 3.11 or newer. To publish an Actor, its Dockerfile must use a `scrapely/actor-python*` base on Python 3.11 or newer, or the project must have no Dockerfile. See [Publishing](https://scrape.ly/docs/publishing.md).

### requirements.txt

List only the packages your code needs, for example `crawlee[beautifulsoup]` or `crawlee[playwright]`. Leave out `scrapely-python`, `scrapely` and `apify`.

### Local runs

`scrapely run` runs your project on your machine with `.venv/bin/python`, falling back to `python3`. It looks for `main.py`, `src/main.py` or the entrypoint you pass with `--entrypoint`. Outside the platform, the SDK uses Crawlee's file-system storage in `./storage`, and it launches a local browser instead of the remote one. Charging, platform events and the platform proxy aren't available.

To `import scrapely` locally, install the SDK into your virtual environment with `pip install scrapely-python`, but keep it out of `requirements.txt`. To test against the platform itself, use `scrapely push` and `scrapely call`, or develop inside a `scrapely/actor-python*` container.

## Imports

```python
from scrapely import Actor, Event
from crawlee.crawlers import BeautifulSoupCrawler, PlaywrightCrawler
```

Crawler classes come from `crawlee.crawlers`. The SDK root re-exports Crawlee's `Dataset`, `KeyValueStore`, `RequestQueue`, `Request`, `Event` and `EventListener`. It also exports Scrape.ly's own `Configuration`, `ProxyConfiguration`, option dataclasses, charging helpers, webhooks, `BrowserConfiguration`, `ScrapelyRequestList` and an exception hierarchy. See the [API reference](https://scrape.ly/docs/sdk-python-reference.md) for the full list.

Importing `scrapely` patches Crawlee's browser pool, Playwright, pyppeteer, and Camoufox. When the Actor has **Use Scrapely browser** turned on, platform launches connect to the [Scrape.ly browser](https://scrape.ly/docs/browser.md); with it off (the default) they launch in the container. See [Remote browser](https://scrape.ly/docs/sdk-python-environment.md#remote-browser).

The base images also ship an `apify` module that re-exports `scrapely`. That means `from apify import Actor` resolves to this SDK.

## Async model

The SDK is async. Most `Actor` methods are coroutines, so you must await them inside an event loop.

These members are synchronous: `Actor.on()`, `Actor.off()`, `Actor.get_env()`, `Actor.get_config()`, `Actor.is_at_home()`, `Actor.is_standby()`, `Actor.get_remaining_time()`, `Actor.get_charging_manager()`, `Actor.new_client()` and `Actor.get_default_instance()`. The `log`, `input`, `exit_code`, `status_message`, `is_paying`, `configuration`, `event_manager` and `apify_client` properties are synchronous too.

## Minimal Actor

Use `async with Actor:`:

```python
import asyncio

from scrapely import Actor


async def main() -> None:
    async with Actor:
        actor_input = await Actor.get_input() or {}
        await Actor.push_data({"url": actor_input.get("url"), "ok": True})


if __name__ == "__main__":
    asyncio.run(main())
```

Entering the block calls `Actor.init()`. Leaving it flushes pending charges, closes events and closes storages. `Actor.main(main)` is an equivalent entrypoint that also calls `sys.exit()` with the run's exit code. See [Lifecycle](https://scrape.ly/docs/sdk-python-lifecycle.md) for the differences.

## How an Actor runs

The platform starts your container with the run context in environment variables. These include the run ID, a scoped API token, the API URL, the default storage IDs, the input, the timeout, the events WebSocket URL, the Scrape.ly browser URL and, when enabled, platform proxy credentials. The SDK reads them during `Actor.init()`.

1. `Actor.init()` connects storage to the Scrape.ly API, connects the events WebSocket and loads pricing information for pay-per-event Actors.
2. Your code reads input with `Actor.get_input()`.
3. Your crawler or code writes results with `Actor.push_data()`, `Actor.set_value()` or an opened storage.
4. The platform sends `systemInfo`, `persistState`, `migrating` and `aborting` events over the WebSocket.
5. On exit, the SDK flushes pending charges, closes the event manager and closes storages.

Always await writes. If you don't, the process can end before a dataset or key-value store write reaches the API.

## Where to go next

| Topic | Page |
| --- | --- |
| `async with Actor`, `init`, `main`, `exit`, `fail`, signals | [Lifecycle](https://scrape.ly/docs/sdk-python-lifecycle.md) |
| `get_input`, secret inputs, `push_data`, `get_value`, `set_value` | [Input & output](https://scrape.ly/docs/sdk-python-input-output.md) |
| Datasets, key-value stores, request queues, storage clients | [Storages](https://scrape.ly/docs/sdk-python-storages.md) |
| Events, `use_state`, migration, status messages | [Events & state](https://scrape.ly/docs/sdk-python-events.md) |
| `call`, `start`, `metamorph`, `reboot`, webhooks, charging, API clients | [Actors & webhooks](https://scrape.ly/docs/sdk-python-actors.md) |
| Environment, Scrape.ly browser, proxy, HTTP serving | [Environment & proxy](https://scrape.ly/docs/sdk-python-environment.md) |
| Errors, troubleshooting, Dockerfiles, deployment | [Errors & deployment](https://scrape.ly/docs/sdk-python-deploy.md) |
| Every exported symbol and signature | [API reference](https://scrape.ly/docs/sdk-python-reference.md) |

To call Actors or read storages from outside an Actor, use the standalone [Python API client](https://scrape.ly/docs/client-python.md).

---

- Previous: [API reference](https://scrape.ly/docs/sdk-node-reference.md)
- Next: [Lifecycle](https://scrape.ly/docs/sdk-python-lifecycle.md)
- All docs: [Docs index](https://scrape.ly/docs.md), [llms.txt](https://scrape.ly/llms.txt)
