Spaces:
Runtime error
Runtime error
### Using `storage_state` to Pre-Load Cookies and LocalStorage | |
Crawl4ai’s `AsyncWebCrawler` lets you preserve and reuse session data, including cookies and localStorage, across multiple runs. By providing a `storage_state`, you can start your crawls already “logged in” or with any other necessary session data—no need to repeat the login flow every time. | |
#### What is `storage_state`? | |
`storage_state` can be: | |
- A dictionary containing cookies and localStorage data. | |
- A path to a JSON file that holds this information. | |
When you pass `storage_state` to the crawler, it applies these cookies and localStorage entries before loading any pages. This means your crawler effectively starts in a known authenticated or pre-configured state. | |
#### Example Structure | |
Here’s an example storage state: | |
```json | |
{ | |
"cookies": [ | |
{ | |
"name": "session", | |
"value": "abcd1234", | |
"domain": "example.com", | |
"path": "/", | |
"expires": 1675363572.037711, | |
"httpOnly": false, | |
"secure": false, | |
"sameSite": "None" | |
} | |
], | |
"origins": [ | |
{ | |
"origin": "https://example.com", | |
"localStorage": [ | |
{ "name": "token", "value": "my_auth_token" }, | |
{ "name": "refreshToken", "value": "my_refresh_token" } | |
] | |
} | |
] | |
} | |
``` | |
This JSON sets a `session` cookie and two localStorage entries (`token` and `refreshToken`) for `https://example.com`. | |
--- | |
### Passing `storage_state` as a Dictionary | |
You can directly provide the data as a dictionary: | |
```python | |
import asyncio | |
from crawl4ai import AsyncWebCrawler | |
async def main(): | |
storage_dict = { | |
"cookies": [ | |
{ | |
"name": "session", | |
"value": "abcd1234", | |
"domain": "example.com", | |
"path": "/", | |
"expires": 1675363572.037711, | |
"httpOnly": False, | |
"secure": False, | |
"sameSite": "None" | |
} | |
], | |
"origins": [ | |
{ | |
"origin": "https://example.com", | |
"localStorage": [ | |
{"name": "token", "value": "my_auth_token"}, | |
{"name": "refreshToken", "value": "my_refresh_token"} | |
] | |
} | |
] | |
} | |
async with AsyncWebCrawler( | |
headless=True, | |
storage_state=storage_dict | |
) as crawler: | |
result = await crawler.arun(url='https://example.com/protected') | |
if result.success: | |
print("Crawl succeeded with pre-loaded session data!") | |
print("Page HTML length:", len(result.html)) | |
if __name__ == "__main__": | |
asyncio.run(main()) | |
``` | |
--- | |
### Passing `storage_state` as a File | |
If you prefer a file-based approach, save the JSON above to `mystate.json` and reference it: | |
```python | |
import asyncio | |
from crawl4ai import AsyncWebCrawler | |
async def main(): | |
async with AsyncWebCrawler( | |
headless=True, | |
storage_state="mystate.json" # Uses a JSON file instead of a dictionary | |
) as crawler: | |
result = await crawler.arun(url='https://example.com/protected') | |
if result.success: | |
print("Crawl succeeded with pre-loaded session data!") | |
print("Page HTML length:", len(result.html)) | |
if __name__ == "__main__": | |
asyncio.run(main()) | |
``` | |
--- | |
### Using `storage_state` to Avoid Repeated Logins (Sign In Once, Use Later) | |
A common scenario is when you need to log in to a site (entering username/password, etc.) to access protected pages. Doing so every crawl is cumbersome. Instead, you can: | |
1. Perform the login once in a hook. | |
2. After login completes, export the resulting `storage_state` to a file. | |
3. On subsequent runs, provide that `storage_state` to skip the login step. | |
**Step-by-Step Example:** | |
**First Run (Perform Login and Save State):** | |
```python | |
import asyncio | |
from crawl4ai import AsyncWebCrawler, CacheMode | |
from crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator | |
async def on_browser_created_hook(browser): | |
# Access the default context and create a page | |
context = browser.contexts[0] | |
page = await context.new_page() | |
# Navigate to the login page | |
await page.goto("https://example.com/login", wait_until="domcontentloaded") | |
# Fill in credentials and submit | |
await page.fill("input[name='username']", "myuser") | |
await page.fill("input[name='password']", "mypassword") | |
await page.click("button[type='submit']") | |
await page.wait_for_load_state("networkidle") | |
# Now the site sets tokens in localStorage and cookies | |
# Export this state to a file so we can reuse it | |
await context.storage_state(path="my_storage_state.json") | |
await page.close() | |
async def main(): | |
# First run: perform login and export the storage_state | |
async with AsyncWebCrawler( | |
headless=True, | |
verbose=True, | |
hooks={"on_browser_created": on_browser_created_hook}, | |
use_persistent_context=True, | |
user_data_dir="./my_user_data" | |
) as crawler: | |
# After on_browser_created_hook runs, we have storage_state saved to my_storage_state.json | |
result = await crawler.arun( | |
url='https://example.com/protected-page', | |
cache_mode=CacheMode.BYPASS, | |
markdown_generator=DefaultMarkdownGenerator(options={"ignore_links": True}), | |
) | |
print("First run result success:", result.success) | |
if result.success: | |
print("Protected page HTML length:", len(result.html)) | |
if __name__ == "__main__": | |
asyncio.run(main()) | |
``` | |
**Second Run (Reuse Saved State, No Login Needed):** | |
```python | |
import asyncio | |
from crawl4ai import AsyncWebCrawler, CacheMode | |
from crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator | |
async def main(): | |
# Second run: no need to hook on_browser_created this time. | |
# Just provide the previously saved storage state. | |
async with AsyncWebCrawler( | |
headless=True, | |
verbose=True, | |
use_persistent_context=True, | |
user_data_dir="./my_user_data", | |
storage_state="my_storage_state.json" # Reuse previously exported state | |
) as crawler: | |
# Now the crawler starts already logged in | |
result = await crawler.arun( | |
url='https://example.com/protected-page', | |
cache_mode=CacheMode.BYPASS, | |
markdown_generator=DefaultMarkdownGenerator(options={"ignore_links": True}), | |
) | |
print("Second run result success:", result.success) | |
if result.success: | |
print("Protected page HTML length:", len(result.html)) | |
if __name__ == "__main__": | |
asyncio.run(main()) | |
``` | |
**What’s Happening Here?** | |
- During the first run, the `on_browser_created_hook` logs into the site. | |
- After logging in, the crawler exports the current session (cookies, localStorage, etc.) to `my_storage_state.json`. | |
- On subsequent runs, passing `storage_state="my_storage_state.json"` starts the browser context with these tokens already in place, skipping the login steps. | |
**Sign Out Scenario:** | |
If the website allows you to sign out by clearing tokens or by navigating to a sign-out URL, you can also run a script that uses `on_browser_created_hook` or `arun` to simulate signing out, then export the resulting `storage_state` again. That would give you a baseline “logged out” state to start fresh from next time. | |
--- | |
### Conclusion | |
By using `storage_state`, you can skip repetitive actions, like logging in, and jump straight into crawling protected content. Whether you provide a file path or a dictionary, this powerful feature helps maintain state between crawls, simplifying your data extraction pipelines. |