fix(sky-8861): block-output download refresh fallback when artifact_ids are missing (#5675)

This commit is contained in:
Shuchang Zheng 2026-04-26 16:56:39 -07:00 committed by GitHub
parent c2f0581390
commit 2250788de3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
73 changed files with 610 additions and 954 deletions

View file

@ -2,7 +2,7 @@
title: Actions Reference
subtitle: Every page action and agent method
description: Reference for all page actions (act, extract, validate, prompt, click, fill, select_option) and agent methods (login, run_task, download_files, run_workflow) with parameters and return types.
slug: developers/browser-automations/actions-reference
slug: browser-automations/actions-reference
keywords:
- act
- extract
@ -550,14 +550,14 @@ console.log(result.output)
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `prompt` | `str` | Yes | Multi-step goal description |
| `data_extraction_schema` | `dict \| str` | No | JSON Schema for structured output. See [Extract Structured Data](/developers/browser-automations/extract-structured-data). |
| `data_extraction_schema` | `dict \| str` | No | JSON Schema for structured output. See [Extract Structured Data](/browser-automations/extract-structured-data). |
| `max_steps` | `int` | No | Cap AI steps. The run terminates with `timed_out` if hit. Controls cost; each step is one AI decision + action cycle. |
| `engine` | `RunEngine` | No | AI engine. Defaults to `skyvern-1.0` in the SDK for backward compatibility. Pass `skyvern-2.0` for the latest model (also the Cloud UI default). Other options: `openai-cua`, `anthropic-cua`, `ui-tars`. |
| `model` | `dict` / `Record<string, unknown>` | No | Override LLM model configuration |
| `url` | `str` / `string` | No | URL to navigate to (defaults to current page URL) |
| `webhook_url` | `str` / `string` | No | Callback URL. Skyvern POSTs the full run result on completion or failure. See [Webhooks](/developers/going-to-production/webhooks). |
| `totp_identifier` | `str` / `string` | No | Identifier for push-based TOTP. See [Handle 2FA](/developers/credentials/handle-2fa). |
| `totp_url` | `str` / `string` | No | Endpoint Skyvern calls to pull TOTP codes. See [Handle 2FA](/developers/credentials/handle-2fa). |
| `webhook_url` | `str` / `string` | No | Callback URL. Skyvern POSTs the full run result on completion or failure. See [Webhooks](/going-to-production/webhooks). |
| `totp_identifier` | `str` / `string` | No | Identifier for push-based TOTP. See [Handle 2FA](/credentials/handle-2fa). |
| `totp_url` | `str` / `string` | No | Endpoint Skyvern calls to pull TOTP codes. See [Handle 2FA](/credentials/handle-2fa). |
| `title` | `str` / `string` | No | Display name for this run |
| `error_code_mapping` | `dict` / `Record<string, string>` | No | Map custom error codes to conditions. Keys are your error codes, values describe when to trigger them. If matched, `output` contains `{"error": "your_code"}`. |
| `user_agent` | `str` / `string` | No | Custom User-Agent header for the browser |
@ -633,7 +633,7 @@ const result = await page.agent.runWorkflow(
| `parameters` | `dict` | No | Workflow input parameters |
| `template` | `bool` | No | Run a template workflow |
| `title` | `str` / `string` | No | Display name for this run |
| `webhook_url` | `str` / `string` | No | Callback URL for run completion. See [Webhooks](/developers/going-to-production/webhooks). |
| `webhook_url` | `str` / `string` | No | Callback URL for run completion. See [Webhooks](/going-to-production/webhooks). |
| `totp_url` | `str` / `string` | No | Endpoint for pulling TOTP codes |
| `totp_identifier` | `str` / `string` | No | Identifier for push-based TOTP |
| `timeout` | `float` | No | Max wait in seconds (default: 1800) |

View file

@ -2,7 +2,7 @@
title: Extract Structured Data
subtitle: Get consistent, typed output from your automations
description: Define JSON Schema extraction schemas for Skyvern tasks to get consistent, typed output. Build schemas for single objects or arrays of items with the interactive schema builder.
slug: developers/browser-automations/extract-structured-data
slug: browser-automations/extract-structured-data
keywords:
- JSON Schema
- extraction schema
@ -703,14 +703,14 @@ If using webhooks, the same `output` field appears in the webhook payload.
<Card
title="Actions Reference"
icon="sliders"
href="/developers/browser-automations/actions-reference"
href="/browser-automations/actions-reference"
>
All available page actions and agent methods
</Card>
<Card
title="Build a Browser Automation"
icon="play"
href="/developers/browser-automations/overview"
href="/browser-automations/overview"
>
Launch a browser, navigate pages, and extract data
</Card>

View file

@ -2,7 +2,7 @@
title: Handle Browsers
subtitle: Launch, connect, configure, and manage browser sessions
description: Launch cloud browsers, connect via CDP, configure proxies and timeouts, open multiple tabs, and manage browser lifecycle for Skyvern automations.
slug: developers/browser-automations/handle-browsers
slug: browser-automations/handle-browsers
keywords:
- launch_cloud_browser
- use_cloud_browser
@ -133,7 +133,7 @@ skyvern = Skyvern.local()
browser = await skyvern.launch_local_browser(headless=False, port=9222)
```
See the [Self-Hosted Browser Configuration](/developers/self-hosted/browser) guide for headless/headful modes, display settings, and Docker setups.
See the [Self-Hosted Browser Configuration](/self-hosted/browser) guide for headless/headful modes, display settings, and Docker setups.
---
@ -188,7 +188,7 @@ await browser.close();
```
</CodeGroup>
Closes the browser and releases cloud resources. If connected to a cloud session, the session ends. Any unsaved state (cookies, localStorage) is lost unless you saved a [browser profile](/developers/optimization/browser-profiles) first.
Closes the browser and releases cloud resources. If connected to a cloud session, the session ends. Any unsaved state (cookies, localStorage) is lost unless you saved a [browser profile](/optimization/browser-profiles) first.
---
@ -226,7 +226,7 @@ Available locations:
| `RESIDENTIAL_CA` | Canada |
| `NONE` | No proxy (direct connection) |
For self-hosted proxy configuration, see [Proxy Setup](/developers/self-hosted/proxy).
For self-hosted proxy configuration, see [Proxy Setup](/self-hosted/proxy).
---
@ -234,9 +234,9 @@ For self-hosted proxy configuration, see [Proxy Setup](/developers/self-hosted/p
Two mechanisms for preserving browser state between automation runs:
**Browser Sessions** keep a browser alive between API calls. Use `create_browser_session` from the [Tasks API](/sdk-reference/tasks/run-task) to create a session, then pass its ID to multiple `run_task` calls. See [Browser Sessions](/developers/optimization/browser-sessions).
**Browser Sessions** keep a browser alive between API calls. Use `create_browser_session` from the [Tasks API](/sdk-reference/tasks/run-task) to create a session, then pass its ID to multiple `run_task` calls. See [Browser Sessions](/optimization/browser-sessions).
**Browser Profiles** save a snapshot of browser state (cookies, localStorage) that persists indefinitely. Create a profile from a completed run, then load it into future runs to skip login. See [Browser Profiles](/developers/optimization/browser-profiles).
**Browser Profiles** save a snapshot of browser state (cookies, localStorage) that persists indefinitely. Create a profile from a completed run, then load it into future runs to skip login. See [Browser Profiles](/optimization/browser-profiles).
---

View file

@ -2,7 +2,7 @@
title: Build a Browser Automation
subtitle: Step-by-step guide to multi-step automations with code
description: Launch a cloud browser, interact with pages using AI and Playwright, chain agent tasks, and build complete browser automations in Python or TypeScript.
slug: developers/browser-automations/overview
slug: browser-automations/overview
keywords:
- launch_cloud_browser
- get_working_page
@ -74,13 +74,13 @@ const page = await browser.getWorkingPage();
The browser stays alive until you call `browser.close()` or the session times out (default: 60 minutes). All pages inside it share cookies, localStorage, and auth state.
For browser launch options (timeouts, proxies, connecting to local browsers), see [Managing Browsers](/developers/browser-automations/handle-browsers).
For browser launch options (timeouts, proxies, connecting to local browsers), see [Managing Browsers](/browser-automations/handle-browsers).
---
## Step 2: Navigate and interact with the page
Once you have a page, you can interact with it using standard Playwright, AI actions, or both. For the full list of available methods and parameters, see the [Actions Reference](/developers/browser-automations/actions-reference).
Once you have a page, you can interact with it using standard Playwright, AI actions, or both. For the full list of available methods and parameters, see the [Actions Reference](/browser-automations/actions-reference).
### Navigate
@ -528,7 +528,7 @@ for (const artifact of artifacts) {
```
</CodeGroup>
For the full artifact type reference and debugging workflows, see [Using Artifacts](/developers/debugging/using-artifacts).
For the full artifact type reference and debugging workflows, see [Using Artifacts](/debugging/using-artifacts).
---
@ -538,14 +538,14 @@ For the full artifact type reference and debugging workflows, see [Using Artifac
<Card
title="Actions Reference"
icon="list"
href="/developers/browser-automations/actions-reference"
href="/browser-automations/actions-reference"
>
Every page action and agent method with parameters and return types
</Card>
<Card
title="Managing Browsers"
icon="browser"
href="/developers/browser-automations/handle-browsers"
href="/browser-automations/handle-browsers"
>
Launch options, multiple tabs, proxies, connecting to local browsers
</Card>

View file

@ -2,7 +2,7 @@
title: Work with Files
subtitle: Download files from websites during browser automations
description: Use agent.download_files to navigate websites, find download links, and retrieve files. Access downloaded files via presigned URLs.
slug: developers/browser-automations/work-with-files
slug: browser-automations/work-with-files
keywords:
- download_files
- downloaded_files
@ -177,4 +177,4 @@ Files downloaded during a workflow accumulate in a temporary directory and can b
## Full reference
- [agent.download_files](/sdk-reference/browser-automation/agent-download-files) - SDK reference with all parameter options
- [Using Artifacts](/developers/debugging/using-artifacts) - access recordings, screenshots, and downloaded files from any run
- [Using Artifacts](/debugging/using-artifacts) - access recordings, screenshots, and downloaded files from any run

View file

@ -13,31 +13,21 @@ keywords:
<div className="cl-page">
<div className="cl-sidebar">
<p className="cl-sidebar-title">TIMELINE</p>
<a href="#v1-0-24" className="cl-sidebar-link">v1.0.24 — Apr 21, 2026</a>
<a href="#v1-0-23" className="cl-sidebar-link">v1.0.23 — Apr 14, 2026</a>
<a href="#v1-0-22" className="cl-sidebar-link">v1.0.22 — Feb 26, 2026</a>
<a href="#v1-0-21" className="cl-sidebar-link">v1.0.21 — Feb 24, 2026</a>
<a href="#v1-0-20" className="cl-sidebar-link">v1.0.20 — Feb 21, 2026</a>
<a href="#v1-0-19" className="cl-sidebar-link">v1.0.19 — Feb 20, 2026</a>
<a href="#v1-0-18" className="cl-sidebar-link">v1.0.18 — Feb 19, 2026</a>
<a href="#v1-0-17" className="cl-sidebar-link">v1.0.17 — Feb 19, 2026</a>
<a href="#v1-0-16" className="cl-sidebar-link">v1.0.16 — Feb 19, 2026</a>
<a href="#v1-0-15" className="cl-sidebar-link">v1.0.15 — Feb 17, 2026</a>
<a href="#v1-0-14" className="cl-sidebar-link">v1.0.14 — Feb 17, 2026</a>
<a href="#v1-0-13" className="cl-sidebar-link">v1.0.13 — Feb 10, 2026</a>
<a href="#v1-0-12" className="cl-sidebar-link">v1.0.12 — Feb 3, 2026</a>
<a href="#v1-0-11" className="cl-sidebar-link">v1.0.11 — Jan 29, 2026</a>
<a href="#v1-0-10" className="cl-sidebar-link">v1.0.10 — Jan 22, 2026</a>
<a href="#v1-0-9" className="cl-sidebar-link">v1.0.9 — Jan 20, 2026</a>
<a href="#v1-0-8" className="cl-sidebar-link">v1.0.8 — Jan 9, 2026</a>
<a href="#week-of-april-21%2C-2026" className="cl-sidebar-link">Week of Apr 21, 2026</a>
<a href="#week-of-april-14%2C-2026" className="cl-sidebar-link">Week of Apr 14, 2026</a>
<a href="#v1-0-22-—-february-26%2C-2026" className="cl-sidebar-link">v1.0.22 — Feb 26, 2026</a>
<a href="#v1-0-21-—-february-24%2C-2026" className="cl-sidebar-link">v1.0.21 — Feb 24, 2026</a>
<a href="#v1-0-18-—-february-19%2C-2026" className="cl-sidebar-link">v1.0.18 — Feb 19, 2026</a>
<a href="#v1-0-17-—-february-19%2C-2026" className="cl-sidebar-link">v1.0.17 — Feb 19, 2026</a>
<a href="#v1-0-16-—-february-19%2C-2026" className="cl-sidebar-link">v1.0.16 — Feb 19, 2026</a>
<a href="#v1-0-15-—-february-17%2C-2026" className="cl-sidebar-link">v1.0.15 — Feb 17, 2026</a>
</div>
<div className="cl-content">
<h1 className="cl-title">Changelog</h1>
<p className="cl-subtitle">New features, improvements, and fixes in Skyvern</p>
<a id="v1-0-24"></a>
<Update label="v1.0.24 — April 21, 2026" description="Copilot reliability, run recordings, 2FA improvements, and more">
<Update label="Week of April 21, 2026" description="Copilot reliability, run recordings, 2FA improvements, and more">
## Improvements
@ -54,8 +44,7 @@ keywords:
</Update>
<a id="v1-0-23"></a>
<Update label="v1.0.23 — April 14, 2026" description="Saudi Arabia proxy, workflow error mapping, smarter caching, MCP OAuth, AI output summaries, and reliability fixes">
<Update label="Week of April 14, 2026" description="Saudi Arabia proxy, workflow error mapping, smarter caching, MCP OAuth, AI output summaries, and reliability fixes">
## New features
@ -96,10 +85,8 @@ keywords:
- Fixed per-step video sync spawning a redundant ffmpeg process on every step, causing CPU spikes and log noise. ([#5559](https://github.com/Skyvern-AI/skyvern/pull/5559))
- Fixed workflow parameter edit and delete buttons being hidden when a parameter name was too long.
- Fixed webhook delivery failing silently when a stored webhook URL had a leading or trailing space. ([#5550](https://github.com/Skyvern-AI/skyvern/pull/5550))
</Update>
<a id="v1-0-22"></a>
<Update label="v1.0.22 — February 26, 2026" description="Adaptive caching, Workflow Trigger block, CLI signup, and more">
## New features
@ -145,7 +132,6 @@ keywords:
</Update>
<a id="v1-0-21"></a>
<Update label="v1.0.21 — February 24, 2026" description="Reserved parameters, data_schema for loops, new LLM models">
## New features
@ -173,35 +159,6 @@ keywords:
</Update>
<a id="v1-0-20"></a>
<Update label="v1.0.20 — February 21, 2026" description="Browser profile testing UI and 2FA verification flow">
## New features
- **Browser Profile Testing UI (Frontend)** — The Browsers page now lets you launch a test run against a saved browser profile to confirm its login state is still valid before scheduling production workflows. ([#4833](https://github.com/Skyvern-AI/skyvern/pull/4833))
- **2FA Verification Code UI and Notifications** — When a workflow pauses for a 2FA code, the UI now shows a clear prompt and pushes a notification so you don't miss it. ([#4787](https://github.com/Skyvern-AI/skyvern/pull/4787))
## Improvements
- **2FA Backend Cleanup** — Refactored the 2FA pipeline to make code delivery more reliable across both the UI form and the API endpoint. ([#4826](https://github.com/Skyvern-AI/skyvern/pull/4826))
</Update>
<a id="v1-0-19"></a>
<Update label="v1.0.19 — February 20, 2026" description="Admin impersonation controls and configuration improvements">
## New features
- **Gated Admin Impersonation for MCP API Keys** — Adds gated admin controls so support engineers can impersonate an organization scope when troubleshooting MCP-based automations, with audit-friendly access controls. ([#4822](https://github.com/Skyvern-AI/skyvern/pull/4822))
## Improvements
- **Environment Variables Override Mounted API Keys** — In Skyvern's Streamlit-based deployment, env vars now take precedence over keys baked into the image, making local overrides simpler. ([#4824](https://github.com/Skyvern-AI/skyvern/pull/4824))
</Update>
<a id="v1-0-18"></a>
<Update label="v1.0.18 — February 19, 2026" description="Browser profile testing and saved-profile workflows">
## New features
@ -214,7 +171,6 @@ keywords:
</Update>
<a id="v1-0-17"></a>
<Update label="v1.0.17 — February 19, 2026" description="Skills package and cached script management">
## New features
@ -225,7 +181,6 @@ keywords:
</Update>
<a id="v1-0-16"></a>
<Update label="v1.0.16 — February 19, 2026" description="2FA detection, full CLI parity, Claude Opus 4.6 CUA">
## New features
@ -247,258 +202,12 @@ keywords:
</Update>
<a id="v1-0-15"></a>
<Update label="v1.0.15 — February 17, 2026" description="Claude Opus 4.6 model support">
## New features
- **Anthropic Claude Opus 4.6** — Added Claude Opus 4.6 as an available LLM engine for web automation tasks. ([#4777](https://github.com/Skyvern-AI/skyvern/pull/4777), [#4778](https://github.com/Skyvern-AI/skyvern/pull/4778))
</Update>
<a id="v1-0-14"></a>
<Update label="v1.0.14 — February 17, 2026" description="Unified Browser Task block, MCP block discovery, and credential editing">
## New features
- **Unified Browser Task Block** — The Navigation V1 and Task V2 blocks have been merged into a single **Browser Task** block. The block now exposes both engines as a dropdown, simplifying the workflow editor and reducing block-type confusion. ([#4695](https://github.com/Skyvern-AI/skyvern/pull/4695))
- **Block Discovery MCP Tools** — Added MCP tools that let AI assistants enumerate available block types and their schemas, plus richer instructions for building workflows through MCP. ([#4683](https://github.com/Skyvern-AI/skyvern/pull/4683))
- **Edit Existing Credentials API** — A new endpoint lets you update credential values without deleting and recreating them, preserving credential IDs across changes. ([#4693](https://github.com/Skyvern-AI/skyvern/pull/4693))
- **Filter Workflow Runs by Error Code and Search Key** — The workflow runs list endpoint now supports `error_code` and `search_key` query parameters for narrowing down failed runs. ([#4694](https://github.com/Skyvern-AI/skyvern/pull/4694))
- **GPT-5 Mini in Model Selector** — GPT-5 Mini is now selectable as an LLM engine. GPT-5 has been hidden in favor of more reliable variants. ([#4686](https://github.com/Skyvern-AI/skyvern/pull/4686))
## Improvements
- **Block Failure Reasons Surfaced in UI** — Every block type now shows its `failure_reason` in the run timeline, making debugging non-obvious failures faster. ([#4672](https://github.com/Skyvern-AI/skyvern/pull/4672))
- **Webhook Payload Truncation in Logs** — Large webhook payloads are now truncated in log entries, keeping logs readable without losing context. ([#4701](https://github.com/Skyvern-AI/skyvern/pull/4701))
## Bug fixes
- Fixed the cursor jumping to the end while editing conditional expressions in the workflow editor. ([#4682](https://github.com/Skyvern-AI/skyvern/pull/4682))
- Fixed dotted Jinja variables (e.g. `{{ block_output.field }}`) rendering incorrectly in the expression preview. ([#4684](https://github.com/Skyvern-AI/skyvern/pull/4684))
- The API now returns 404 instead of 500 when a workflow is not found. ([#4699](https://github.com/Skyvern-AI/skyvern/pull/4699))
</Update>
<a id="v1-0-13"></a>
<Update label="v1.0.13 — February 10, 2026" description="Cached scripts for control-flow blocks, OTEL, and workflow editor polish">
## New features
- **Conditional Block Caching** — The script cache now supports Conditional blocks, so workflows that branch based on page state can replay from cache instead of re-running the AI agent. ([#4642](https://github.com/Skyvern-AI/skyvern/pull/4642))
- **OpenTelemetry Backend** — Skyvern can now export metrics, traces, and logs to any OTEL-compatible collector for centralized observability. ([#4632](https://github.com/Skyvern-AI/skyvern/pull/4632))
- **Workflow API Route Reorganization** — Workflow API endpoints have been split into focused routers, making the OpenAPI surface easier to navigate. ([#4628](https://github.com/Skyvern-AI/skyvern/pull/4628))
## Improvements
- **Workflow Copilot Auto-Opens for Empty Workflows** — When you create a new workflow with no blocks yet, the Workflow Copilot opens by default to help you get started. ([#4625](https://github.com/Skyvern-AI/skyvern/pull/4625))
- **Run Workflow Button Moved to Top** — The Run button now lives at the top of the workflow editor for easier access. ([#4626](https://github.com/Skyvern-AI/skyvern/pull/4626))
- **Skip LLM for Single-Match Location Autocomplete** — Location autocomplete now skips the LLM call when only one option matches the user's input, reducing cost and latency. ([#4631](https://github.com/Skyvern-AI/skyvern/pull/4631))
- **Improved Version History Icon** — The workflow version history button now uses an icon that better represents document versions. ([#4640](https://github.com/Skyvern-AI/skyvern/pull/4640))
## Bug fixes
- Fixed `ForLoop` blocks failing to execute under script caching (regression from v1.0.12). ([#4630](https://github.com/Skyvern-AI/skyvern/pull/4630))
- Fixed `ActionDragPath` subscript error in CUA drag-action parsing. ([#4623](https://github.com/Skyvern-AI/skyvern/pull/4623))
- Fixed cron-scheduled tasks getting stuck with "task not found" errors. ([#4627](https://github.com/Skyvern-AI/skyvern/pull/4627))
- Fixed parameter creation dialog not clearing default-value state when switching to credential type. ([#4622](https://github.com/Skyvern-AI/skyvern/pull/4622))
- Fixed debugger loop-block visual overlap when the status row appeared. ([#4641](https://github.com/Skyvern-AI/skyvern/pull/4641))
</Update>
<a id="v1-0-12"></a>
<Update label="v1.0.12 — February 3, 2026" description="Task V2 termination, ForLoop caching, and cleaner conditional debugging">
## New features
- **Task V2 Termination** — Task V2 (the planner-agent-validator system) can now be terminated mid-run via API, matching the cancel behavior already available for Task V1. ([#4589](https://github.com/Skyvern-AI/skyvern/pull/4589))
- **ForLoop Block Caching** — Cached scripts now support `ForLoop` blocks. Workflows that iterate over lists can replay from cache after the first successful run. ([#4600](https://github.com/Skyvern-AI/skyvern/pull/4600))
- **Conditional Block Caching** — Initial support for caching workflows that include conditional branching. ([#4603](https://github.com/Skyvern-AI/skyvern/pull/4603))
- **`run_with` Parameter for Run Task** — The `run_task` endpoint now accepts a `run_with` parameter so you can target Task V2 (or future variants) without changing the endpoint. ([#4576](https://github.com/Skyvern-AI/skyvern/pull/4576))
- **`skyvern run dev` Command** — A new CLI command spins up a Superset workspace alongside the standard dev environment for local analytics work. ([#4593](https://github.com/Skyvern-AI/skyvern/pull/4593))
## Improvements
- **All Branch Evaluations Shown in Conditional Block Timeline** — The run timeline now shows every conditional branch's evaluation result, not just the chosen one — useful when debugging "why did it pick that branch?" ([#4577](https://github.com/Skyvern-AI/skyvern/pull/4577))
- **Sidebar Expand/Collapse Icon** — Replaced the pin icon with a chevron, matching common conventions. ([#4586](https://github.com/Skyvern-AI/skyvern/pull/4586))
- **PDF Parsing Token Cap** — PDF parsing now caps token volume per request to avoid total failure on very large documents. ([#4602](https://github.com/Skyvern-AI/skyvern/pull/4602))
- **`DATABASE_STRING` Parameter on Quickstart** — `skyvern quickstart` now accepts a `DATABASE_STRING` argument for explicit DB connection configuration. ([#4580](https://github.com/Skyvern-AI/skyvern/pull/4580))
## Bug fixes
- Fixed credentials not clearing from the Login block when deselected from the picker. ([#4581](https://github.com/Skyvern-AI/skyvern/pull/4581))
- Fixed workflow run timeline missing recent steps until a manual refresh. ([#4587](https://github.com/Skyvern-AI/skyvern/pull/4587))
- Fixed the workflow editor showing spurious "unsaved changes" when switching between conditional branches. ([#4588](https://github.com/Skyvern-AI/skyvern/pull/4588))
</Update>
<a id="v1-0-11"></a>
<Update label="v1.0.11 — January 29, 2026" description="Workflow Copilot GA, Browser Sessions v2 frontend, and TOTP improvements">
## New features
- **Workflow Copilot Generally Available** — The Workflow Copilot is now enabled for all users. Describe what you want in natural language and it generates a multi-block workflow you can edit. ([#4533](https://github.com/Skyvern-AI/skyvern/pull/4533))
- **Browser Sessions v2 Frontend** — The new browser session management UI lands on the Browsers page, building on the v2 backend shipped in v1.0.10. ([#4514](https://github.com/Skyvern-AI/skyvern/pull/4514))
- **TOTP Endpoint OTP Type Filter** — The TOTP listing endpoint now accepts an `otp_type` query parameter for filtering numeric codes vs. magic links. ([#4529](https://github.com/Skyvern-AI/skyvern/pull/4529))
- **Mintlify Documentation Setup** — Skyvern's documentation site moves to Mintlify, with redirects for the legacy Fern URLs. ([#4516](https://github.com/Skyvern-AI/skyvern/pull/4516))
## Improvements
- **Async File I/O via aiofiles** — Replaced blocking file I/O with `aiofiles` throughout the agent runtime, improving throughput on I/O-heavy workloads. ([#4520](https://github.com/Skyvern-AI/skyvern/pull/4520))
- **Cached Experimentation Provider TTL** — `BaseExperimentationProvider` now caches feature-flag lookups with a per-item TTL, reducing pressure on the experimentation backend. ([#4536](https://github.com/Skyvern-AI/skyvern/pull/4536), [#4540](https://github.com/Skyvern-AI/skyvern/pull/4540))
## Bug fixes
- Fixed `ai_fallback` not being read correctly from the database for cached workflow runs. ([#4524](https://github.com/Skyvern-AI/skyvern/pull/4524))
- Fixed iframe-tree extraction crashing when the page raised a transient exception. ([#4530](https://github.com/Skyvern-AI/skyvern/pull/4530))
- Fixed the workflow version comparison view ordering versions on the wrong sides. ([#4531](https://github.com/Skyvern-AI/skyvern/pull/4531))
- Fixed the workflow history panel scroll behavior in debug mode. ([#4532](https://github.com/Skyvern-AI/skyvern/pull/4532))
- Fixed `TypeError` when comparing offset-naive and offset-aware datetimes during workflow scheduling. ([#4534](https://github.com/Skyvern-AI/skyvern/pull/4534))
- Fixed schema regeneration overwriting unchanged block field names. ([#4535](https://github.com/Skyvern-AI/skyvern/pull/4535))
- Fixed `uvicorn` reload breaking on Windows due to async event loop policy. ([#4538](https://github.com/Skyvern-AI/skyvern/pull/4538))
</Update>
<a id="v1-0-10"></a>
<Update label="v1.0.10 — January 22, 2026" description="Browser Sessions v2 backend, general text CAPTCHA, and TOTP webhook retries">
## New features
- **Browser Sessions v2 (Backend)** — A new persistent browser session architecture with cleaner lifecycle management, better resource reuse, and improved reliability for long-running automations. The frontend follows in v1.0.11. ([#4515](https://github.com/Skyvern-AI/skyvern/pull/4515))
- **General Text CAPTCHA Solver** — Skyvern can now solve a wider range of text-based CAPTCHAs without site-specific configuration. ([#4517](https://github.com/Skyvern-AI/skyvern/pull/4517))
- **TOTP Webhook Retries** — TOTP webhook delivery now retries automatically on transient failures, reducing the rate of "no code received" errors during 2FA flows. ([#4518](https://github.com/Skyvern-AI/skyvern/pull/4518))
- **Block-Label Validation in `run_blocks`** — The `run_blocks` endpoint now validates block labels up front, returning a clear error instead of failing partway through execution. ([#4500](https://github.com/Skyvern-AI/skyvern/pull/4500))
## Improvements
- **Confirmation Dialog Shows Affected Blocks** — Deleting a parameter or block now lists every block that references it, so you don't accidentally break downstream logic. ([#4519](https://github.com/Skyvern-AI/skyvern/pull/4519))
- **Workflow Updates Return 409 on Race** — Concurrent workflow updates now return HTTP 409 instead of silently overwriting each other. ([#4510](https://github.com/Skyvern-AI/skyvern/pull/4510))
- **Tiktoken Caching** — Tokenizer instances are now cached, cutting per-step overhead on token counting. ([#4521](https://github.com/Skyvern-AI/skyvern/pull/4521))
## Bug fixes
- Fixed a Gemini 3 Flash cache-creation bug that caused false-positive fallback detection. ([#4502](https://github.com/Skyvern-AI/skyvern/pull/4502))
- Fixed Bitwarden item-ID format validation rejecting valid IDs. ([#4508](https://github.com/Skyvern-AI/skyvern/pull/4508))
- Fixed dangling block-output and parameter references after rename or deletion. ([#4507](https://github.com/Skyvern-AI/skyvern/pull/4507))
</Update>
<a id="v1-0-9"></a>
<Update label="v1.0.9 — January 20, 2026" description="Print PDF block, Workflow Copilot streaming, and persistent session billing">
## New features
- **Print PDF Block** — A new workflow block that prints the current page to PDF and saves it to your run's downloaded files, useful for archiving receipts, invoices, and reports. ([#4452](https://github.com/Skyvern-AI/skyvern/pull/4452))
- **HTTP File Downloads** — The HTTP Request block can now download files directly via HTTP (not just GET JSON), enabling workflows that pull artifacts from authenticated APIs. ([#4440](https://github.com/Skyvern-AI/skyvern/pull/4440))
- **Workflow Copilot Streaming with Cancel** — The Workflow Copilot now streams its responses with a cancel button, so you can stop generation mid-stream if you want to refine your prompt. ([#4437](https://github.com/Skyvern-AI/skyvern/pull/4437), [#4456](https://github.com/Skyvern-AI/skyvern/pull/4456))
- **"Execute on Any Outcome" (Finally) Block Option** — Blocks can now be configured to run regardless of whether prior blocks succeeded, enabling cleanup steps and "always send report" workflows. ([#4443](https://github.com/Skyvern-AI/skyvern/pull/4443))
- **Persistent Browser Session Uptime Billing** — Billing v2 now meters persistent browser session uptime separately, with PostHog feature flags controlling rollout. ([#4444](https://github.com/Skyvern-AI/skyvern/pull/4444))
- **GPT-5 Mini Flex Engine** — Added GPT-5 Mini Flex as an available LLM engine. ([#4432](https://github.com/Skyvern-AI/skyvern/pull/4432))
- **Clipboard Copy over HTTP** — The browser now exposes clipboard copy functionality that works in HTTP-served browser sessions, not just HTTPS. ([#4446](https://github.com/Skyvern-AI/skyvern/pull/4446))
## Improvements
- **HTTP Block Boolean and Integer Templates** — The HTTP Request block now correctly passes boolean and integer template values without coercing them to strings. ([#4435](https://github.com/Skyvern-AI/skyvern/pull/4435))
- **Bitwarden and Azure Vault Tooltips** — Added inline help tooltips explaining how to set up Bitwarden and Azure Key Vault credential sources. ([#4447](https://github.com/Skyvern-AI/skyvern/pull/4447))
- **Smaller S3 Objects Use STANDARD Tier** — Storage cost optimization: small artifacts now use STANDARD instead of GLACIER_IR. ([#4453](https://github.com/Skyvern-AI/skyvern/pull/4453))
- **Reduced Max SVG Parsing** — Lowered the SVG parsing cap to prevent runaway memory usage on pathological pages. ([#4430](https://github.com/Skyvern-AI/skyvern/pull/4430))
</Update>
<a id="v1-0-8"></a>
<Update label="v1.0.8 — January 9, 2026" description="Workflow Copilot v1, Azure secret storage, and per-action billing">
## New features
- **Workflow Copilot v1** — The first version of the Workflow Copilot ships behind a feature flag. Describe a workflow in natural language and the copilot generates blocks, parameters, and connections you can edit on the canvas. ([#4401](https://github.com/Skyvern-AI/skyvern/pull/4401), [#4413](https://github.com/Skyvern-AI/skyvern/pull/4413), [#4416](https://github.com/Skyvern-AI/skyvern/pull/4416), [#4423](https://github.com/Skyvern-AI/skyvern/pull/4423))
- **Per-Action Credit Billing (Billing v2)** — A new billing model meters credits per browser action instead of per step, giving more predictable cost behavior on action-heavy workflows. ([#4398](https://github.com/Skyvern-AI/skyvern/pull/4398))
- **Azure Key Vault Secret Storage** — Skyvern can now store and retrieve credentials from Azure Key Vault as a managed secret backend. ([#4384](https://github.com/Skyvern-AI/skyvern/pull/4384))
- **Conditional Inside Conditional** — Conditional blocks can now be nested inside other conditional blocks for richer branching logic. ([#4362](https://github.com/Skyvern-AI/skyvern/pull/4362))
- **Reference Workflow Output in Sub-Blocks** — Blocks can now reference upstream `workflow_output` variables, simplifying multi-stage workflows. ([#4414](https://github.com/Skyvern-AI/skyvern/pull/4414))
- **Browser Type Choice for Persistent Browser Sessions** — Persistent sessions now let you choose the browser type (Chromium, etc.) at create time. ([#4406](https://github.com/Skyvern-AI/skyvern/pull/4406))
- **Browser Extension Support for PBS** — Persistent browser sessions can launch with a specified browser extension. ([#4364](https://github.com/Skyvern-AI/skyvern/pull/4364))
- **Step Count in Webhooks and Run Payloads** — Webhook payloads and `get_run` responses now include `step_count` for cost reconciliation. ([#4410](https://github.com/Skyvern-AI/skyvern/pull/4410))
- **PH (Philippines) Proxy Location** — Added Philippines as a residential proxy option. ([#4395](https://github.com/Skyvern-AI/skyvern/pull/4395))
- **TextPromptBlock Artifact Storage** — TextPromptBlock now saves the LLM prompt and response as run artifacts for debugging. ([#4361](https://github.com/Skyvern-AI/skyvern/pull/4361))
- **ActionScreenshot Linking** — Actions in the run timeline now link directly to the screenshot captured at the time of execution, so you can see what the agent saw when it made each decision. ([#4403](https://github.com/Skyvern-AI/skyvern/pull/4403), [#4404](https://github.com/Skyvern-AI/skyvern/pull/4404))
## Improvements
- **Clearer Errors for Missing Workflow Parameters** — Missing required parameters now return a clear HTTP 400 instead of HTTP 500. ([#4380](https://github.com/Skyvern-AI/skyvern/pull/4380))
- **Empty-String Defaults for String Parameters** — Workflow string parameters without explicit defaults now initialize to `""` instead of `null`, matching common Jinja-template expectations. ([#4382](https://github.com/Skyvern-AI/skyvern/pull/4382))
- **HAR Files Use Zstd Compression** — HAR archives now ship as `.har.zst`, cutting storage size significantly with no fidelity loss. ([#4420](https://github.com/Skyvern-AI/skyvern/pull/4420))
- **Hydrated Workflow Title in Run Responses** — `workflow_run` responses now include the workflow title for cleaner logging without an extra API call. ([#4363](https://github.com/Skyvern-AI/skyvern/pull/4363))
- **Cached Workflow-Script Lookup** — `get_workflow_script_by_cache_key_value` is now cached and post-action execution can re-enable code generation. ([#4385](https://github.com/Skyvern-AI/skyvern/pull/4385))
- **Updated Datacenter Proxy Provider** — Datacenter proxies now route through a new provider with broader IP coverage. ([#4386](https://github.com/Skyvern-AI/skyvern/pull/4386))
- **Improved Conditional NL Branch Tooltip** — Updated tooltip and placeholder text on conditional blocks to better describe how natural-language branches are evaluated. ([#4368](https://github.com/Skyvern-AI/skyvern/pull/4368), [#4369](https://github.com/Skyvern-AI/skyvern/pull/4369))
- **OLLAMA Vision Support Toggle** — Added `OLLAMA_SUPPORTS_VISION` env var to enable vision-capable Ollama models. ([#4351](https://github.com/Skyvern-AI/skyvern/pull/4351))
## Bug fixes
- Fixed older credentials becoming inaccessible after an internal schema change. ([#4358](https://github.com/Skyvern-AI/skyvern/pull/4358))
- Fixed scrolling actions misfiring on pages with overflow-hidden ancestors. ([#4389](https://github.com/Skyvern-AI/skyvern/pull/4389))
- Fixed `close_browser_on_completion` not being honored during workflow run cleanup. ([#4381](https://github.com/Skyvern-AI/skyvern/pull/4381))
- Fixed run-ID generation collisions under high concurrency. ([#4383](https://github.com/Skyvern-AI/skyvern/pull/4383))
- Fixed empty browser-extension config crashing PBS launch. ([#4365](https://github.com/Skyvern-AI/skyvern/pull/4365))
- Fixed wrong screenshots being attached to certain actions. ([#4400](https://github.com/Skyvern-AI/skyvern/pull/4400))
- Fixed nested DB connection management in workflow execution. ([#4402](https://github.com/Skyvern-AI/skyvern/pull/4402), [#4411](https://github.com/Skyvern-AI/skyvern/pull/4411))
- Fixed `local variable not defined` errors in cached-action execution. ([#4376](https://github.com/Skyvern-AI/skyvern/pull/4376))
- Fixed artifacts endpoint incorrectly including `api/` in the path. ([#4417](https://github.com/Skyvern-AI/skyvern/pull/4417))
- Fixed S3 storage class selection for small objects (`_get_storage_class_for_org`). ([#4424](https://github.com/Skyvern-AI/skyvern/pull/4424))
- Fixed cached actions executing without a brief settling delay. ([#4418](https://github.com/Skyvern-AI/skyvern/pull/4418))
</Update>
</div>

View file

@ -21,7 +21,7 @@ Profiles are ideal when you:
- Need multiple workflows to share the same authenticated state
<Note>
Looking to manage profiles from code? See the [API & SDK guide](/developers/optimization/browser-profiles) instead.
Looking to manage profiles from code? See the [API & SDK guide](/optimization/browser-profiles) instead.
</Note>
---
@ -111,7 +111,7 @@ For sites with short-lived sessions (banks, healthcare portals), refresh profile
<Card
title="Browser Profiles (API)"
icon="code"
href="/developers/optimization/browser-profiles"
href="/optimization/browser-profiles"
>
Create and manage profiles programmatically
</Card>

View file

@ -15,7 +15,7 @@ keywords:
A **browser session** is a live browser instance that stays open between runs. Cookies, login state, cart contents, and page context all persist, like keeping a browser tab open. Use sessions when you need back-to-back tasks to share state, or when you want to interact with the browser yourself between automated steps.
<Note>
Looking to use browser sessions from code? See the [API & SDK guide](/developers/optimization/browser-sessions) instead.
Looking to use browser sessions from code? See the [API & SDK guide](/optimization/browser-sessions) instead.
</Note>
---
@ -174,7 +174,7 @@ Use a session when you need a live browser right now. Use a [profile](/cloud/bro
<Card
title="Browser Sessions (API)"
icon="code"
href="/developers/optimization/browser-sessions"
href="/optimization/browser-sessions"
>
Create and manage sessions programmatically
</Card>

View file

@ -15,7 +15,7 @@ keywords:
Parameters let you create reusable workflows that accept different input values each time they run. Instead of hardcoding a URL or search term into a block, you reference a parameter and fill in the value when you run the workflow.
This page covers parameters in the Cloud UI workflow editor. If you're building automations in code, parameters are just function arguments. See [Browser Automation](/developers/browser-automations/overview) for the code-first approach.
This page covers parameters in the Cloud UI workflow editor. If you're building automations in code, parameters are just function arguments. See [Browser Automation](/browser-automations/overview) for the code-first approach.
---

View file

@ -16,7 +16,7 @@ keywords:
Workflows are multi-step automations built visually in the Cloud UI. You drag blocks onto a canvas, wire them together, configure each one, and run the whole sequence with a click. No code required. Workflows can be versioned, shared across your team, scheduled on a cron, and run with different parameters each time.
If you prefer writing automation code in Python or TypeScript, see [Browser Automation](/developers/browser-automations/overview) in the developer docs. Both approaches handle multi-step work across pages. Workflows are the visual path, browser automations are the code path.
If you prefer writing automation code in Python or TypeScript, see [Browser Automation](/browser-automations/overview) in the developer docs. Both approaches handle multi-step work across pages. Workflows are the visual path, browser automations are the code path.
<Info>
**Workflows vs. Browser Automation:** Workflows are defined in this visual editor and run from the Cloud UI (or [triggered from code](/cloud/building-workflows/run-from-code)). Browser automations are written in Python/TypeScript using Page, Agent, and Browser. Choose based on whether your team prefers a visual editor or a code editor.

View file

@ -19,7 +19,7 @@ keywords:
Workflows are built from blocks. Each block performs one specific operation: navigating a page, extracting data, making an API call, or branching logic. This page covers every block type available in the Cloud UI [workflow editor](/cloud/building-workflows/build-a-workflow), grouped by category.
If you're writing automations in code instead, the equivalent operations are Page and Agent methods. See the [Actions Reference](/developers/browser-automations/actions-reference) for the code-first counterparts to these blocks.
If you're writing automations in code instead, the equivalent operations are Page and Agent methods. See the [Actions Reference](/browser-automations/actions-reference) for the code-first counterparts to these blocks.
<Frame caption="To add a block in your workflow, click the **+** button, click on Add block, then select the block type from the menu.">
<img src="/images/cloud/add-block-ui.png" alt="how to add a block to a workflow in Skyvern" />
@ -98,7 +98,7 @@ Additional fields in **Advanced Settings** (Skyvern 1.0 only):
*Plus [common browser fields](#common-fields).*
<Frame>
<img width="400" src="/images/cloud/br_task_block.png" alt="Browser Task block configuration with URL and prompt fields" />
<img src="/images/cloud/br_task_block.png" alt="Browser Task block configuration with URL and prompt fields" />
</Frame>
<Tip>
@ -135,7 +135,7 @@ Extract structured data from the current page using AI.
*Plus [common browser fields](#common-fields).*
<Frame>
<img width="400" src="/images/cloud/extract_block.png" alt="Extraction block configuration with Data Extraction Goal and Data Schema fields" />
<img src="/images/cloud/extract_block.png" alt="Extraction block configuration with Data Extraction Goal and Data Schema fields" />
</Frame>
### Login
@ -157,7 +157,7 @@ Additional fields in **Advanced Settings:**
*Plus [common browser fields](#common-fields).*
<Frame>
<img width="400" src="/images/cloud/login_block.png" alt="Login block configuration with URL, Login Goal, and Credential fields" />
<img src="/images/cloud/login_block.png" alt="Login block configuration with URL, Login Goal, and Credential fields" />
</Frame>
### Go to URL
@ -169,7 +169,7 @@ Navigate the browser directly to a specific URL without AI interaction.
| **URL** | text | **(Required)** The URL to navigate to. Supports [parameter references](/cloud/building-workflows/add-parameters#referencing-parameters-in-blocks). |
<Frame>
<img width="400" src="/images/cloud/url_block.png" alt="Go to URL block configuration with URL field" />
<img src="/images/cloud/url_block.png" alt="Go to URL block configuration with URL field" />
</Frame>
### Print Page
@ -190,7 +190,7 @@ Additional fields in **Advanced Settings:**
| **Landscape** | boolean | Use landscape orientation |
<Frame>
<img width="400" src="/images/cloud/print_block.png" alt="Print Page block configuration with page format, print background, and headers & footers options" />
<img src="/images/cloud/print_block.png" alt="Print Page block configuration with page format, print background, and headers & footers options" />
</Frame>
---
@ -208,7 +208,7 @@ Send text to the LLM for processing without browser interaction. Useful for summ
| **Data Schema** | JSON | Expected output structure. Enable the checkbox to reveal the editor. Click **Generate with AI** to auto-suggest a schema. |
<Frame>
<img width="400" src="/images/cloud/text_block.png" alt="Text Prompt block configuration with Prompt, Model, and Data Schema fields" />
<img src="/images/cloud/text_block.png" alt="Text Prompt block configuration with Prompt, Model, and Data Schema fields" />
</Frame>
### File Parser
@ -222,7 +222,7 @@ Parse PDFs, CSVs, Excel files, and images to extract structured data.
| **Model** | selector | Which LLM model to use |
<Frame>
<img width="400" src="/images/cloud/file_parse_block.png" alt="File Parser block configuration with File URL, Data Schema, and Model fields" />
<img src="/images/cloud/file_parse_block.png" alt="File Parser block configuration with File URL, Data Schema, and Model fields" />
</Frame>
---
@ -243,7 +243,7 @@ Inside loop blocks, use these [reserved variables](/cloud/building-workflows/add
- `{{ current_index }}`: the iteration number (0-based)
<Frame>
<img width="400" src="/images/cloud/block-loop-config.png" alt="Loop block configuration" />
<img src="/images/cloud/block-loop-config.png" alt="Loop block configuration" />
</Frame>
### Conditional
@ -261,7 +261,7 @@ Branch the workflow based on conditions. The UI shows branches as tabs (A, B, C,
```
<Frame>
<img width="400" src="/images/cloud/conditional_block.png" alt="Conditional block configuration with branch expressions" />
<img src="/images/cloud/conditional_block.png" alt="Conditional block configuration with branch expressions" />
</Frame>
### AI Validation
@ -281,7 +281,7 @@ Additional fields in **Advanced Settings:**
| **Input Parameters** | select | Parameters to evaluate |
<Frame>
<img width="400" src="/images/cloud/ai_val_block.png" alt="AI Validation block configuration with Complete if and Terminate if fields" />
<img src="/images/cloud/ai_val_block.png" alt="AI Validation block configuration with Complete if and Terminate if fields" />
</Frame>
### Code
@ -294,7 +294,7 @@ Execute custom Python code. Input parameters are available as global variables.
| **Input Parameters** | select | Parameters available as globals in the code |
<Frame>
<img width="400" src="/images/cloud/code_block.png" alt="Code block configuration with Python code editor and Input Parameters field" />
<img src="/images/cloud/code_block.png" alt="Code block configuration with Python code editor and Input Parameters field" />
</Frame>
### Wait
@ -306,7 +306,7 @@ Pause workflow execution for a specified duration.
| **Wait in Seconds** | number | Seconds to wait (0300) |
<Frame>
<img width="400" src="/images/cloud/wait_block.png" alt="Wait block configuration with Wait in Seconds field" />
<img src="/images/cloud/wait_block.png" alt="Wait block configuration with Wait in Seconds field" />
</Frame>
---
@ -332,7 +332,7 @@ Additional fields in **Advanced Settings:**
*Plus [common browser fields](#common-fields).*
<Frame>
<img width="400" src="/images/cloud/download_block.png" alt="File Download block configuration with URL, Download Goal, and Download Timeout fields" />
<img src="/images/cloud/download_block.png" alt="File Download block configuration with URL, Download Goal, and Download Timeout fields" />
</Frame>
### Cloud Storage Upload
@ -366,7 +366,7 @@ Upload downloaded files to S3 or Azure Blob Storage.
</Accordion>
<Frame>
<img width="400" src="/images/cloud/cloud_block.png" alt="Cloud Storage Upload block configuration with Storage Type and Folder Path fields" />
<img src="/images/cloud/cloud_block.png" alt="Cloud Storage Upload block configuration with Storage Type and Folder Path fields" />
</Frame>
---
@ -385,7 +385,7 @@ Send an email notification, optionally with file attachments from previous block
| **File Attachments** | text | Path to files to attach |
<Frame>
<img width="400" src="/images/cloud/email_block.png" alt="Send Email block configuration with Recipients, Subject, Body, and File Attachments fields" />
<img src="/images/cloud/email_block.png" alt="Send Email block configuration with Recipients, Subject, Body, and File Attachments fields" />
</Frame>
### HTTP Request
@ -411,7 +411,7 @@ Additional fields in **Advanced Settings:**
| **Download Filename** | text | Filename for the saved response (shown when Save Response as File is enabled) |
<Frame>
<img width="400" src="/images/cloud/http_block.png" alt="HTTP Request block configuration with Method, URL, Headers, and Body fields" />
<img src="/images/cloud/http_block.png" alt="HTTP Request block configuration with Method, URL, Headers, and Body fields" />
</Frame>
### Human Interaction
@ -439,5 +439,5 @@ Additional fields in **Advanced Settings:**
| **Negative Button Label** | text | Label for the rejection action (default: "Reject") |
<Frame>
<img width="400" src="/images/cloud/human_block.png" alt="Human Interaction block configuration with Instructions For Human and Timeout fields" />
<img src="/images/cloud/human_block.png" alt="Human Interaction block configuration with Instructions For Human and Timeout fields" />
</Frame>

View file

@ -15,7 +15,7 @@ keywords:
Workflows are multi-step automations built visually in the Cloud UI. Once you've [built a workflow](/cloud/building-workflows/build-a-workflow), the **Workflows** page is where you organize, share, and manage them. Each workflow is a reusable sequence of blocks that you can run with different inputs each time.
If you're building automations in code instead, see the [Browser Automation](/developers/browser-automations/overview) developer docs.
If you're building automations in code instead, see the [Browser Automation](/browser-automations/overview) developer docs.
Click **Workflows** in the left sidebar to open it.

View file

@ -17,7 +17,7 @@ keywords:
If you've built a workflow in the Cloud UI and want to trigger it from your codebase, this page shows how. You can run workflows on demand, poll for results, and set up recurring schedules using the Python SDK, TypeScript SDK, or REST API.
This is for workflows defined in the visual editor. If you're writing your entire automation in code (no workflow editor involved), see [Browser Automation](/developers/browser-automations/overview) instead.
This is for workflows defined in the visual editor. If you're writing your entire automation in code (no workflow editor involved), see [Browser Automation](/browser-automations/overview) instead.
---
@ -213,7 +213,7 @@ curl -X POST "https://api.skyvern.com/v1/run/workflows" \
```
</CodeGroup>
The webhook payload contains the same data as the polling response. See [Webhooks](/developers/going-to-production/webhooks) for authentication and retry options.
The webhook payload contains the same data as the polling response. See [Webhooks](/going-to-production/webhooks) for authentication and retry options.
### Response fields

View file

@ -139,7 +139,7 @@ To change which workflow a schedule runs, delete the schedule and create a new o
<Card
title="Cost Control"
icon="gauge"
href="/developers/optimization/cost-control"
href="/optimization/cost-control"
>
Manage costs for recurring automations
</Card>

View file

@ -1,7 +1,7 @@
---
title: Core Concepts
subtitle: The building blocks of every automation in the Skyvern dashboard
description: Understand tasks, workflows, blocks, runs, browser sessions, browser profiles, and credentials in the Skyvern Cloud UI — what each is, where to find it, and how it fits together.
subtitle: The building blocks of Skyvern automations
description: Understand the building blocks of Skyvern automations
slug: cloud/getting-started/core-concepts
keywords:
- task
@ -10,238 +10,10 @@ keywords:
- browser session
- browser profile
- credential
- run
- schedule
- engine
- run status
---
Every automation you build in Skyvern Cloud is composed of the same nine building blocks. This page is a quick tour of each one — what it is, where you find it in the dashboard, and when to reach for it.
import CoreConceptsContent from "/snippets/core-concepts-content.mdx";
If you've already poked around the dashboard, this map will tie what you've seen to the underlying concepts.
---
## Tasks
A **Task** is a single automation job. You describe what you want, Skyvern opens a browser and does it.
You create tasks from the **Discover** page. Type your prompt and target URL into the input bar, pick an engine, and hit send.
<img src="/images/cloud/discover-page-overview.png" alt="Discover page where you create one-off tasks" />
Tasks are the right starting point for one-off automations, ad-hoc data extraction, or quickly testing whether an idea is feasible before turning it into a workflow.
When you outgrow a single task — you need parameters, branching, loops, or to run the same flow on a schedule — graduate to a Workflow.
<Card title="Run a task →" icon="play" href="/cloud/getting-started/run-a-task">
Walkthrough of every option on the Discover page.
</Card>
---
## Workflows
A **Workflow** is a reusable automation built by chaining blocks together on a visual canvas. Workflows are versioned, parameterized, and shareable across your team.
You build them on the **Workflows** page. Click any workflow to open the editor, where blocks appear as connected nodes you can drag and configure.
<img src="/images/cloud/workflow-editor-overview.png" alt="Workflow editor with blocks chained together" />
Use a workflow when:
- The same flow needs to run repeatedly with different inputs
- You need to loop over a list, branch on a condition, or pass data between steps
- You want to schedule the automation to run on a cadence
- You want a teammate to be able to re-run it without re-deriving the logic
<Card title="Build a workflow →" icon="diagram-project" href="/cloud/building-workflows/build-a-workflow">
Tutorial covering blocks, parameters, branching, and execution.
</Card>
---
## Blocks
**Blocks** are the units a workflow is built from. Each block performs one thing — navigate, log in, extract data, branch on a condition, send an email — and passes its output to the next block.
In the workflow editor, click the **+** button on any node to insert a new block. The picker groups every available block by category.
<img src="/images/cloud/add-block-panel.png" alt="Block picker with categories and block types" />
There are 20+ block types organized into:
- **Browser automation** — Browser Task, Browser Action, Login, Extraction, Go to URL, Print Page
- **Data and extraction** — Text Prompt, File Parser
- **Control flow** — Loop, Conditional, AI Validation, Code, Wait
- **Files** — File Download, Cloud Storage Upload
- **Communication** — Send Email, HTTP Request, Human Interaction
Each block has its own configuration panel. The full reference, with every field for every block, lives at [Workflow Blocks](/cloud/building-workflows/configure-blocks).
---
## Runs
Every time a task or workflow executes, Skyvern creates a **Run** — a record of what happened, with a video, screenshots, action log, and any extracted data.
The **Runs** page is your history. Filter by status, search by run ID, click any row to drill in.
<img src="/images/cloud/run-history-overview.png" alt="Runs page showing execution history with statuses" />
Inside a run detail page you'll find:
- **Live viewer / recording** — full video of the browser as it executed
- **Actions** — every step the agent took, with the LLM's reasoning
- **Output** — the structured data extracted (matches the schema you defined)
- **Code** — auto-generated Python/TypeScript/cURL to reproduce this run via API
- **Downloaded files** — anything Skyvern saved, with signed URLs and checksums
A run can be `queued`, `running`, `completed`, `failed`, `terminated`, `timed_out`, or `canceled`. You're billed per **step** — one screenshot + LLM decision + browser action.
<Card title="Read run details →" icon="list-check" href="/cloud/viewing-results/run-details">
How to interpret the actions tab, recordings, and output.
</Card>
---
## Browser sessions
A **browser session** is a live browser instance you keep open across multiple runs. Sessions preserve everything that lives in the browser — cookies, login state, cached pages, the current tab — so a follow-up task picks up exactly where the previous one left off.
You manage sessions on the **Browsers** page. Create a session, run tasks against it, then close it when you're done.
<img src="/images/cloud/browsers-page-overview.png" alt="Browsers page with active session and details" />
Sessions are perfect when you want to:
- Log in once, then run a sequence of tasks behind that login
- Hand off a partially-completed flow between an agent and a human (Take Control)
- Keep a long-running automation warm without re-authenticating each step
Sessions live for 5 minutes to 24 hours (default 60 minutes). When the timer ends or you close it manually, the browser is destroyed and its state goes with it.
<Card title="Browser sessions →" icon="window" href="/cloud/browser-management/browser-sessions">
Create, attach, and reuse sessions across runs.
</Card>
---
## Browser profiles
A **browser profile** is the persistent counterpart to a session. Where a session is a live browser that times out, a profile is a saved snapshot — cookies, auth tokens, local storage — that you can reload weeks later to skip the login flow entirely.
Profiles are listed on the **Browsers** page under the Profiles tab. You create one from any completed run, then attach it to future runs to start in an already-authenticated state.
| | Browser session | Browser profile |
|---|---|---|
| **Live or saved?** | Live, in-memory browser | Saved snapshot of state |
| **Lifetime** | 5 min 24 hr | Indefinite |
| **Best for** | Chaining tasks in real time | Skipping login on repeat runs |
<Card title="Browser profiles →" icon="floppy-disk" href="/cloud/browser-management/browser-profiles">
Save and reuse authenticated state across days or weeks.
</Card>
---
## Credentials
A **credential** is a stored login, credit card, or 2FA secret that Skyvern injects directly into the browser at runtime. Credentials are encrypted at rest and **never sent to the LLM** — the agent decides where the password field is, and the value is filled in via the browser layer.
The **Credentials** page is where you manage them.
<img src="/images/cloud/credentials-overview.png" alt="Credentials page with password and credit card credentials" />
Three credential types are supported:
- **Password** — username + password, optionally with a TOTP secret or email/SMS 2FA
- **Credit card** — card number, expiry, CVC, billing address
- **Secret** — any single value you want to keep out of the LLM context
You can also sync credentials from **Bitwarden**, **1Password**, or **Azure Key Vault** instead of storing them in Skyvern.
<Card title="Credentials overview →" icon="lock" href="/cloud/managing-credentials/credentials-overview">
Security model, supported types, and external vault integration.
</Card>
---
## Schedules
A **schedule** runs a workflow automatically on a recurring cadence. You set a cron expression and timezone, and Skyvern fires the workflow at every interval — no manual trigger needed.
Schedules are configured per workflow. Open any workflow's actions menu and choose **Schedule**.
<Frame>
<img src="/images/cloud/create-sched-form.png" alt="Schedule form with cron expression and timezone" width="300" />
</Frame>
Use schedules for daily reports, hourly monitoring, periodic data syncs, or anything that should "just keep running" without you remembering to click Run.
<Card title="Scheduling →" icon="calendar" href="/cloud/building-workflows/scheduling">
Cron syntax, timezones, and managing scheduled runs.
</Card>
---
## Engines
An **engine** is the AI model Skyvern uses to drive the browser. Different engines have different strengths — speed, accuracy on complex pages, cost — and you can pick one per task or per block.
The engine picker appears on the Discover page (for tasks) and on every browser-driven block in the workflow editor.
| Engine | When to use |
|--------|-------------|
| **Skyvern 2.0** | Default. Best balance of accuracy and speed for most automations. |
| **Skyvern 1.0** | Lighter and faster for simple, single-page interactions. |
| **OpenAI CUA** | OpenAI's Computer Use Agent. Good for visual reasoning. |
| **Anthropic CUA** | Anthropic's Claude Computer Use. Strong at multi-step planning. |
| **UI-TARS** | Lightweight CUA model option. |
If you're not sure, leave it on the default. Switch engines if you hit accuracy issues on a specific site.
---
## How they fit together
```mermaid
flowchart LR
A[Task] -->|Single job, one prompt| R1[Run]
W[Workflow] -->|Reusable, multi-step| R2[Run]
W -->|Composed of| B[Blocks]
S[Schedule] -->|Triggers| W
R1 & R2 -->|Optionally use| BS[Browser Session]
BS -->|Snapshot to| BP[Browser Profile]
BP -->|Restored by| R1
BP -->|Restored by| R2
R1 & R2 -->|Inject at runtime| C[Credentials]
R1 & R2 -->|Driven by| E[Engine]
```
A typical day in the dashboard:
1. **Prototype** with a Task on the Discover page. Iterate on the prompt until it works.
2. **Productionize** by turning the prompt into a Workflow with Blocks, Parameters, and a Schedule.
3. **Persist state** by saving a Browser Profile after the first authenticated run, so future runs skip login.
4. **Audit** every execution on the Runs page — recording, actions, output, downloaded files.
---
## Next steps
<CardGroup cols={2}>
<Card
title="Run Your First Task"
icon="play"
href="/cloud/getting-started/run-your-first-task"
>
Hands-on tutorial — go from prompt to extracted data in a few minutes.
</Card>
<Card
title="Build a Workflow"
icon="diagram-project"
href="/cloud/building-workflows/build-a-workflow"
>
Wire blocks together into a reusable, parameterized automation.
</Card>
</CardGroup>
<CoreConceptsContent />

View file

@ -1,25 +0,0 @@
---
title: MCP Server
subtitle: Connect AI assistants to browser automation via Model Context Protocol
description: Install and configure Skyvern's MCP server so Claude Desktop, Claude Code, Cursor, Windsurf, Codex, Hermes, OpenClaw, and other AI tools can run browser automations from the Skyvern Cloud dashboard over OAuth or API key.
slug: cloud/getting-started/mcp
keywords:
- MCP
- Model Context Protocol
- OAuth
- Claude Desktop
- Claude Code
- Cursor
- Windsurf
- Codex
- Hermes
- OpenClaw
- MCPorter
- AI assistant
- tools
- streamable-http
---
import McpContent from "/snippets/mcp-content.mdx";
<McpContent />

View file

@ -20,7 +20,7 @@ New to Skyvern? The [homepage](/) covers how Skyvern works under the hood, built
</Tip>
<Note>
Looking to integrate Skyvern into your own app? See the [Quickstart](/developers/getting-started/quickstart) instead.
Looking to integrate Skyvern into your own app? See the [Quickstart](/getting-started/quickstart) instead.
</Note>
## The dashboard
@ -87,7 +87,7 @@ That's it. The next guide walks you through this flow with a real example.
<Card
title="Core Concepts"
icon="book"
href="/developers/getting-started/core-concepts"
href="/getting-started/core-concepts"
>
Understand tasks, workflows, and other foundational concepts
</Card>

View file

@ -348,10 +348,10 @@ The response from polling (`get_run`) and webhooks have slightly different struc
### Artifacts
Every run captures recordings, screenshots, and logs. See [Using Artifacts](/developers/debugging/using-artifacts) for retrieval and the full artifact type reference.
Every run captures recordings, screenshots, and logs. See [Using Artifacts](/debugging/using-artifacts) for retrieval and the full artifact type reference.
---
<Note>
For multi-step automations that chain multiple actions, see [Browser Automation](/developers/browser-automations/overview).
For multi-step automations that chain multiple actions, see [Browser Automation](/browser-automations/overview).
</Note>

View file

@ -134,7 +134,7 @@ Now that you've seen the basic flow, here are a few ideas to try next:
<Card
title="Core Concepts"
icon="book"
href="/developers/getting-started/core-concepts"
href="/getting-started/core-concepts"
>
Understand tasks, workflows, and other building blocks
</Card>

View file

@ -97,7 +97,7 @@ The annotated screenshots (`screenshot_llm`) and parsed action lists (`llm_respo
<Card
title="Using Artifacts (API)"
icon="code"
href="/developers/debugging/using-artifacts"
href="/debugging/using-artifacts"
>
Full API reference for artifact retrieval
</Card>

View file

@ -1239,7 +1239,7 @@ Create the workflow from your definition file and execute it.
<Card title="File Operations" icon="file" href="/cloud/building-workflows/configure-blocks">
Download, parse, and upload files in workflows
</Card>
<Card title="Error Handling" icon="triangle-exclamation" href="/developers/going-to-production/error-handling">
<Card title="Error Handling" icon="triangle-exclamation" href="/going-to-production/error-handling">
Handle failures and retries in production
</Card>
</CardGroup>

View file

@ -24,7 +24,7 @@ This cookbook extracts two datasets from [OpenEMR](https://www.open-emr.org/), a
## Prerequisites
- A [Skyvern Cloud](https://app.skyvern.com) account or [self-hosted](/developers/self-hosted/overview) deployment
- A [Skyvern Cloud](https://app.skyvern.com) account or [self-hosted](/self-hosted/overview) deployment
- The Skyvern SDK (for API usage)
<CodeGroup>
@ -103,7 +103,7 @@ Route the browser through a residential IP to bypass WAF/bot detection. The demo
</Tab>
</Tabs>
See [Proxy & Geolocation](/developers/going-to-production/proxy-geolocation) for all available locations.
See [Proxy & Geolocation](/going-to-production/proxy-geolocation) for all available locations.
---
@ -263,7 +263,7 @@ Log in once, save the browser state as a profile, and skip login on future runs.
</Tabs>
<Note>
`persist_browser_session` is a workflow definition property. Set it when creating the workflow, not when running it. See [Browser Profiles](/developers/optimization/browser-profiles) for the full lifecycle.
`persist_browser_session` is a workflow definition property. Set it when creating the workflow, not when running it. See [Browser Profiles](/optimization/browser-profiles) for the full lifecycle.
</Note>
---
@ -397,7 +397,7 @@ The demo resets daily and community users add test patients, so exact records ma
</Note>
<Note>
Browser profiles cannot be used directly with standalone tasks. Create a [browser session](/developers/optimization/browser-sessions) from the profile first, then pass the session ID. See [Pagination with browser sessions](#pagination-with-browser-sessions) below for the full pattern.
Browser profiles cannot be used directly with standalone tasks. Create a [browser session](/optimization/browser-sessions) from the profile first, then pass the session ID. See [Pagination with browser sessions](#pagination-with-browser-sessions) below for the full pattern.
</Note>
---
@ -510,7 +510,7 @@ Navigate to **Reports > Visits > Superbill**, set a date range, and extract the
## Pagination with browser sessions
A [Browser Profile](/developers/optimization/browser-profiles) is a saved snapshot. A [Browser Session](/developers/optimization/browser-sessions) is a live browser instance that persists between tasks. Use sessions to paginate: extract page 1, click Next, extract page 2.
A [Browser Profile](/optimization/browser-profiles) is a saved snapshot. A [Browser Session](/optimization/browser-sessions) is a live browser instance that persists between tasks. Use sessions to paginate: extract page 1, click Next, extract page 2.
<Tabs>
<Tab title="Cloud UI">
@ -786,7 +786,7 @@ OpenEMR can timeout or show session-expired pages. Use `error_code_mapping` on w
</Tab>
</Tabs>
See [Error Handling](/developers/going-to-production/error-handling) and [CAPTCHA & Bot Bypass](/developers/features/captcha-and-bot-bypass) for more.
See [Error Handling](/going-to-production/error-handling) and [CAPTCHA & Bot Bypass](/features/captcha-and-bot-bypass) for more.
---
@ -1062,7 +1062,7 @@ This workflow combines everything: navigate to the Patient Finder, extract demog
| Error mapping + retries | Recover from session timeouts |
<Tip>
The OpenEMR demo resets daily at 8:00 AM UTC, so profiles expire every day. In production, re-run your login workflow weekly or whenever extractions fail with auth errors. See [Browser Profiles](/developers/optimization/browser-profiles) for the refresh pattern.
The OpenEMR demo resets daily at 8:00 AM UTC, so profiles expire every day. In production, re-run your login workflow weekly or whenever extractions fail with auth errors. See [Browser Profiles](/optimization/browser-profiles) for the refresh pattern.
</Tip>
---
@ -1073,14 +1073,14 @@ The OpenEMR demo resets daily at 8:00 AM UTC, so profiles expire every day. In p
<Card
title="Browser Profiles"
icon="user"
href="/developers/optimization/browser-profiles"
href="/optimization/browser-profiles"
>
Full lifecycle: create, refresh, and delete saved browser state
</Card>
<Card
title="Proxy & Geolocation"
icon="globe"
href="/developers/going-to-production/proxy-geolocation"
href="/going-to-production/proxy-geolocation"
>
All proxy locations and country-specific routing options
</Card>
@ -1094,7 +1094,7 @@ The OpenEMR demo resets daily at 8:00 AM UTC, so profiles expire every day. In p
<Card
title="Error Handling"
icon="triangle-exclamation"
href="/developers/going-to-production/error-handling"
href="/going-to-production/error-handling"
>
Error code mapping, failure classification, and retry strategies
</Card>

View file

@ -1155,7 +1155,7 @@ Create the workflow from your definition file and execute it.
<Card title="File Operations" icon="file" href="/cloud/building-workflows/configure-blocks">
Upload and parse files in workflows
</Card>
<Card title="Error Handling" icon="triangle-exclamation" href="/developers/going-to-production/error-handling">
<Card title="Error Handling" icon="triangle-exclamation" href="/going-to-production/error-handling">
Handle failures and retries in production
</Card>
</CardGroup>

View file

@ -2,7 +2,7 @@
title: Handle 2FA
subtitle: Configure two-factor authentication for automated logins
description: Configure two-factor authentication for Skyvern automations using TOTP secrets, pushed verification codes, pull-based endpoints, or magic links. Supports Bitwarden TOTP integration.
slug: developers/credentials/handle-2fa
slug: credentials/handle-2fa
keywords:
- TOTP
- 2FA
@ -507,10 +507,10 @@ Skyvern only returns codes from the last 10 minutes (configurable via `TOTP_LIFE
## Next steps
<CardGroup cols={2}>
<Card title="Store Credentials" icon="key" href="/developers/credentials/store-credentials">
<Card title="Store Credentials" icon="key" href="/credentials/store-credentials">
Set up your credential vault integration
</Card>
<Card title="Troubleshooting" icon="wrench" href="/developers/credentials/troubleshooting-login">
<Card title="Troubleshooting" icon="wrench" href="/credentials/troubleshooting-login">
Debug 2FA and login failures
</Card>
</CardGroup>

View file

@ -2,7 +2,7 @@
title: Store Credentials
subtitle: Securely manage login credentials, credit cards, and API secrets
description: Create, manage, and delete credentials using Skyvern's credential API. Store passwords, credit cards, and API secrets in Bitwarden, 1Password, Azure Key Vault, or a custom vault.
slug: developers/credentials/store-credentials
slug: credentials/store-credentials
keywords:
- create_credential
- get_credentials
@ -486,10 +486,10 @@ When you view a run's artifacts or recordings, you'll see placeholder values lik
## Next steps
<CardGroup cols={2}>
<Card title="Handle 2FA" icon="shield" href="/developers/credentials/handle-2fa">
<Card title="Handle 2FA" icon="shield" href="/credentials/handle-2fa">
Set up two-factor authentication for your automations
</Card>
<Card title="Troubleshooting" icon="wrench" href="/developers/credentials/troubleshooting-login">
<Card title="Troubleshooting" icon="wrench" href="/credentials/troubleshooting-login">
Debug common login failures
</Card>
</CardGroup>

View file

@ -2,7 +2,7 @@
title: Troubleshooting Login Failures
subtitle: Debug common authentication issues in your automations
description: Debug common login failures in Skyvern automations including credential errors, expired 2FA codes, CAPTCHA blocks, SSO redirects, and multi-step login flows. Includes a step-by-step debugging checklist.
slug: developers/credentials/troubleshooting-login
slug: credentials/troubleshooting-login
keywords:
- login failure
- debug
@ -340,10 +340,10 @@ Contact [support@skyvern.com](mailto:support@skyvern.com) or join our [Discord](
## Next steps
<CardGroup cols={2}>
<Card title="Store Credentials" icon="key" href="/developers/credentials/store-credentials">
<Card title="Store Credentials" icon="key" href="/credentials/store-credentials">
Review credential setup
</Card>
<Card title="Handle 2FA" icon="shield" href="/developers/credentials/handle-2fa">
<Card title="Handle 2FA" icon="shield" href="/credentials/handle-2fa">
Configure two-factor authentication
</Card>
</CardGroup>

View file

@ -2,7 +2,7 @@
title: Frequently Asked Questions
subtitle: Common questions and answers from the Skyvern community
description: Answers to common Skyvern questions covering troubleshooting failed tasks, workflow parameters, credentials, scheduling, proxy configuration, API polling, data extraction, and LLM model selection.
slug: developers/debugging/faq
slug: debugging/faq
keywords:
- FAQ
- common questions
@ -28,7 +28,7 @@ Common causes:
- **`timed_out`**: Exceeded `max_steps`. Increase it or simplify the task
- **`failed`**: System error (browser crash, network failure)
See the [Troubleshooting Guide](/developers/debugging/troubleshooting-guide) for detailed steps.
See the [Troubleshooting Guide](/debugging/troubleshooting-guide) for detailed steps.
</Accordion>
<Accordion title="Why is the AI clicking the wrong element?">
@ -115,7 +115,7 @@ Yes. Skyvern has built-in cron-based scheduling for workflows. You define a cron
- **Cloud UI**: Create and manage schedules from the [Schedules page](/cloud/building-workflows/scheduling)
- **API**: Use the [scheduling API](/cloud/building-workflows/run-from-code#create-a-schedule) to create, update, enable/disable, and delete schedules programmatically
Scheduled runs appear in [Run History](/cloud/viewing-results/run-history) with a calendar icon badge. Set up a [webhook](/developers/going-to-production/webhooks) to get notified when scheduled runs complete.
Scheduled runs appear in [Run History](/cloud/viewing-results/run-history) with a calendar icon badge. Set up a [webhook](/going-to-production/webhooks) to get notified when scheduled runs complete.
</Accordion>
<Accordion title="Why isn't my workflow using the parameter values I passed?">
@ -193,7 +193,7 @@ while True:
await asyncio.sleep(5)
```
Or use [webhooks](/developers/going-to-production/webhooks) to get notified when runs complete without polling.
Or use [webhooks](/going-to-production/webhooks) to get notified when runs complete without polling.
</Accordion>
<Accordion title="Where can I find extracted data after a run completes?">
@ -262,7 +262,7 @@ Skyvern has built-in CAPTCHA solving for common types, but some sites use advanc
2. Create a new TOTP credential with your authenticator secret
3. Reference the TOTP credential in your workflow's login block
The AI will automatically fetch and enter the TOTP code when it encounters a 2FA prompt. See [TOTP Setup](/developers/credentials/totp) for detailed instructions.
The AI will automatically fetch and enter the TOTP code when it encounters a 2FA prompt. See [TOTP Setup](/credentials/totp) for detailed instructions.
</Accordion>
<Accordion title="How do I handle email OTP verification?">
@ -333,7 +333,7 @@ If persistent, contact support with your run IDs.
- An LLM API key (OpenAI, Anthropic, Azure, Gemini, or Ollama)
- Docker (optional, for containerized deployment)
Run `skyvern init` for an interactive setup wizard. See the [Quickstart](/developers/getting-started/quickstart) for full instructions.
Run `skyvern init` for an interactive setup wizard. See the [Quickstart](/getting-started/quickstart) for full instructions.
</Accordion>
<Accordion title="How do I update my self-hosted Skyvern instance?">
@ -393,7 +393,7 @@ Go to [Settings > Billing](https://app.skyvern.com/billing) to download invoices
<Card
title="Troubleshooting Guide"
icon="wrench"
href="/developers/debugging/troubleshooting-guide"
href="/debugging/troubleshooting-guide"
>
Step-by-step debugging for failed runs
</Card>

View file

@ -2,7 +2,7 @@
title: Observability with Laminar
subtitle: Add observability to your Skyvern automations with Laminar
description: Integrate Laminar observability into Skyvern to capture traces of automation runs, track LLM call latency and token usage, monitor failure rates, and debug performance across tasks and workflows.
slug: developers/debugging/observability-with-laminar
slug: debugging/observability-with-laminar
keywords:
- Laminar
- traces
@ -20,7 +20,7 @@ keywords:
- **Self-hosted**: Skyvern's server can export full traces to Laminar, including every LLM call (prompts, responses, token usage), browser actions, and workflow step execution. See [self-hosted tracing setup](#self-hosted-tracing-setup) below.
<Tip>
Laminar traces complement [artifacts](/developers/debugging/using-artifacts). Use artifacts for per-run debugging (screenshots, recordings, logs) and Laminar for tracking patterns across runs (failure rates, response times, and which tasks are slowest).
Laminar traces complement [artifacts](/debugging/using-artifacts). Use artifacts for per-run debugging (screenshots, recordings, logs) and Laminar for tracking patterns across runs (failure rates, response times, and which tasks are slowest).
</Tip>
<Note>
@ -215,14 +215,14 @@ No code changes needed. Once the env vars are set, traces appear in your Laminar
<Card
title="Using Artifacts"
icon="file-lines"
href="/developers/debugging/using-artifacts"
href="/debugging/using-artifacts"
>
Per-run recordings, screenshots, logs, and network data
</Card>
<Card
title="Troubleshooting Guide"
icon="wrench"
href="/developers/debugging/troubleshooting-guide"
href="/debugging/troubleshooting-guide"
>
Common issues and how to fix them
</Card>

View file

@ -2,7 +2,7 @@
title: Troubleshooting Guide
subtitle: Common issues, step timeline, and when to adjust what
description: Diagnose and fix common Skyvern run failures using the step timeline, artifacts, and run status. Covers issues like wrong output, timeouts, CAPTCHA blocks, login failures, and element detection problems.
slug: developers/debugging/troubleshooting-guide
slug: debugging/troubleshooting-guide
keywords:
- step timeline
- wrong output
@ -172,7 +172,7 @@ curl -X GET "https://api.skyvern.com/v1/runs/$RUN_ID/artifacts?artifact_type=scr
```
</CodeGroup>
See [Using Artifacts](/developers/debugging/using-artifacts) for the full list of artifact types.
See [Using Artifacts](/debugging/using-artifacts) for the full list of artifact types.
---
@ -372,14 +372,14 @@ See [Using Artifacts](/developers/debugging/using-artifacts) for the full list o
<Card
title="Using Artifacts"
icon="file-lines"
href="/developers/debugging/using-artifacts"
href="/debugging/using-artifacts"
>
Detailed reference for all artifact types
</Card>
<Card
title="Reliability Tips"
icon="shield-check"
href="/developers/going-to-production/reliability-tips"
href="/going-to-production/reliability-tips"
>
Write prompts that fail less often
</Card>

View file

@ -2,7 +2,7 @@
title: Using Artifacts
subtitle: Access recordings, screenshots, logs, and network data for every run
description: Retrieve and inspect artifacts from Skyvern runs including browser recordings, screenshots, AI reasoning logs, DOM element trees, network HAR files, and Playwright traces to debug failures and unexpected results.
slug: developers/debugging/using-artifacts
slug: debugging/using-artifacts
keywords:
- artifact
- recording
@ -208,14 +208,14 @@ These contain structured execution data.
<Card
title="Troubleshooting Guide"
icon="wrench"
href="/developers/debugging/troubleshooting-guide"
href="/debugging/troubleshooting-guide"
>
Common issues and how to fix them
</Card>
<Card
title="Error Handling"
icon="triangle-exclamation"
href="/developers/going-to-production/error-handling"
href="/going-to-production/error-handling"
>
Map errors to custom codes for programmatic handling
</Card>

View file

@ -1,27 +0,0 @@
---
title: MCP Server
subtitle: Connect AI assistants to browser automation via Model Context Protocol
description: Install and configure Skyvern's MCP server so Claude Desktop, Claude Code, Cursor, Windsurf, Codex, Hermes, OpenClaw, and other AI tools can run browser automations against Skyvern Cloud or a self-hosted instance over OAuth, API key, or local stdio.
slug: developers/getting-started/mcp
keywords:
- MCP
- Model Context Protocol
- OAuth
- Claude Desktop
- Claude Code
- Cursor
- Windsurf
- Codex
- Hermes
- OpenClaw
- MCPorter
- AI assistant
- tools
- stdio
- streamable-http
- self-hosted
---
import McpContent from "/snippets/mcp-content.mdx";
<McpContent />

View file

@ -58,25 +58,9 @@
"cloud/getting-started/introduction",
"cloud/getting-started/core-concepts",
"cloud/getting-started/ai-agents-quickstart",
"cloud/getting-started/overview",
"cloud/getting-started/mcp"
"cloud/getting-started/overview"
]
},
{
"group": "Building Workflows",
"pages": [
"cloud/building-workflows/build-a-workflow",
"cloud/building-workflows/manage-workflows",
"cloud/building-workflows/add-parameters",
"cloud/building-workflows/run-a-workflow",
"cloud/building-workflows/scheduling",
"cloud/building-workflows/run-from-code"
]
},
{
"group": "Workflow Blocks",
"pages": ["cloud/building-workflows/configure-blocks"]
},
{
"group": "Running Tasks",
"pages": [
@ -86,6 +70,18 @@
"cloud/getting-started/run-from-code"
]
},
{
"group": "Building Workflows",
"pages": [
"cloud/building-workflows/build-a-workflow",
"cloud/building-workflows/manage-workflows",
"cloud/building-workflows/add-parameters",
"cloud/building-workflows/configure-blocks",
"cloud/building-workflows/run-a-workflow",
"cloud/building-workflows/scheduling",
"cloud/building-workflows/run-from-code"
]
},
{
"group": "Re-using Browsers",
"pages": [
@ -111,15 +107,6 @@
"cloud/managing-credentials/external-providers"
]
},
{
"group": "Integrations",
"pages": [
"integrations/zapier",
"integrations/make",
"integrations/n8n",
"integrations/workato"
]
},
{
"group": "Account & Settings",
"pages": [
@ -128,6 +115,15 @@
"cloud/account-settings/organization-settings",
"cloud/account-settings/profile-settings"
]
},
{
"group": "Integrations",
"pages": [
"integrations/zapier",
"integrations/make",
"integrations/n8n",
"integrations/workato"
]
}
]
},
@ -137,81 +133,78 @@
{
"group": "Getting Started",
"pages": [
"developers/getting-started/introduction",
"developers/getting-started/core-concepts",
"developers/getting-started/quickstart",
"developers/getting-started/ai-agents-quickstart",
"developers/getting-started/mcp",
"getting-started/introduction",
"getting-started/core-concepts",
"getting-started/quickstart",
"getting-started/ai-agents-quickstart",
"integrations/mcp",
"integrations/cli"
]
},
{
"group": "Core Features",
"pages": [
"developers/features/captcha-and-bot-bypass",
"developers/features/browser-sessions",
"developers/features/proxy-and-geo-targeting",
"developers/features/authentication-and-2fa",
"developers/features/code-caching"
"features/captcha-and-bot-bypass",
"features/browser-sessions",
"features/proxy-and-geo-targeting",
"features/authentication-and-2fa",
"features/code-caching"
]
},
{
"group": "Browser Automation",
"pages": [
"developers/browser-automations/overview",
"developers/browser-automations/extract-structured-data",
"developers/browser-automations/work-with-files",
"developers/browser-automations/handle-browsers"
"browser-automations/overview",
"browser-automations/actions-reference",
"browser-automations/extract-structured-data",
"browser-automations/work-with-files",
"browser-automations/handle-browsers"
]
},
{
"group": "Workflow Blocks",
"pages": ["developers/browser-automations/actions-reference"]
},
{
"group": "Handling Authentication",
"pages": [
"developers/credentials/store-credentials",
"developers/credentials/handle-2fa",
"developers/credentials/troubleshooting-login"
"credentials/store-credentials",
"credentials/handle-2fa",
"credentials/troubleshooting-login"
]
},
{
"group": "Optimization",
"pages": [
"developers/optimization/browser-sessions",
"developers/optimization/browser-profiles",
"developers/optimization/cost-control"
"optimization/browser-sessions",
"optimization/browser-profiles",
"optimization/cost-control"
]
},
{
"group": "Going to Production",
"pages": [
"developers/going-to-production/webhooks",
"developers/going-to-production/proxy-geolocation",
"developers/going-to-production/error-handling",
"developers/going-to-production/reliability-tips"
"going-to-production/webhooks",
"going-to-production/proxy-geolocation",
"going-to-production/error-handling",
"going-to-production/reliability-tips"
]
},
{
"group": "Debugging",
"pages": [
"developers/debugging/using-artifacts",
"developers/debugging/troubleshooting-guide",
"developers/debugging/observability-with-laminar",
"developers/debugging/faq"
"debugging/using-artifacts",
"debugging/troubleshooting-guide",
"debugging/observability-with-laminar",
"debugging/faq"
]
},
{
"group": "Self-Hosted Deployment",
"pages": [
"developers/self-hosted/overview",
"developers/self-hosted/docker",
"developers/self-hosted/llm-configuration",
"developers/self-hosted/browser",
"developers/self-hosted/proxy",
"developers/self-hosted/kubernetes",
"developers/self-hosted/storage",
"self-hosted/overview",
"self-hosted/docker",
"self-hosted/llm-configuration",
"self-hosted/browser",
"self-hosted/proxy",
"self-hosted/kubernetes",
"self-hosted/storage",
"integrations/local-llms"
]
}
@ -371,13 +364,14 @@
"navbar": {
"links": [
{
"label": "Get API Key",
"href": "https://app.skyvern.com/settings"
"label": "Dashboard",
"href": "https://app.skyvern.com"
}
],
"primary": {
"type": "github",
"href": "https://github.com/Skyvern-AI/skyvern"
"type": "button",
"label": "Get API Key",
"href": "https://app.skyvern.com/settings/"
}
},
"footer": {
@ -414,7 +408,7 @@
"redirects": [
{
"source": "/going-to-production/captcha-bot-detection",
"destination": "/developers/features/captcha-and-bot-bypass"
"destination": "/features/captcha-and-bot-bypass"
},
{
"source": "/sdk-reference/browser-automation/find",
@ -490,15 +484,15 @@
},
{
"source": "/introduction",
"destination": "/developers/getting-started/quickstart"
"destination": "/getting-started/quickstart"
},
{
"source": "/getting-started/skyvern-in-action",
"destination": "/developers/getting-started/core-concepts"
"destination": "/getting-started/core-concepts"
},
{
"source": "/getting-started/prompting-guide",
"destination": "/developers/debugging/troubleshooting-guide"
"destination": "/debugging/troubleshooting-guide"
},
{
"source": "/running-tasks/run-tasks",
@ -506,7 +500,7 @@
},
{
"source": "/running-tasks/visualizing-results",
"destination": "/developers/debugging/using-artifacts"
"destination": "/debugging/using-artifacts"
},
{
"source": "/running-tasks/cancel-runs",
@ -514,15 +508,15 @@
},
{
"source": "/running-tasks/webhooks-faq",
"destination": "/developers/going-to-production/webhooks"
"destination": "/going-to-production/webhooks"
},
{
"source": "/running-tasks/connect-local-browser",
"destination": "/developers/self-hosted/browser"
"destination": "/self-hosted/browser"
},
{
"source": "/running-tasks/proxy-location",
"destination": "/developers/going-to-production/proxy-geolocation"
"destination": "/going-to-production/proxy-geolocation"
},
{
"source": "/running-tasks/advanced-features",
@ -542,7 +536,7 @@
},
{
"source": "/running-automations/extract-structured-data",
"destination": "/developers/browser-automations/extract-structured-data"
"destination": "/browser-automations/extract-structured-data"
},
{
"source": "/workflows/manage-workflows",
@ -562,7 +556,7 @@
},
{
"source": "/workflows/consistent-workflows",
"destination": "/developers/going-to-production/reliability-tips"
"destination": "/going-to-production/reliability-tips"
},
{
"source": "/workflows/running-workflows",
@ -590,35 +584,35 @@
},
{
"source": "/multi-step-automations/overview",
"destination": "/developers/browser-automations/overview"
"destination": "/browser-automations/overview"
},
{
"source": "/multi-step-automations/actions-reference",
"destination": "/developers/browser-automations/actions-reference"
"destination": "/browser-automations/actions-reference"
},
{
"source": "/multi-step-automations/extract-structured-data",
"destination": "/developers/browser-automations/extract-structured-data"
"destination": "/browser-automations/extract-structured-data"
},
{
"source": "/multi-step-automations/work-with-files",
"destination": "/developers/browser-automations/work-with-files"
"destination": "/browser-automations/work-with-files"
},
{
"source": "/multi-step-automations/handle-browsers",
"destination": "/developers/browser-automations/handle-browsers"
"destination": "/browser-automations/handle-browsers"
},
{
"source": "/multi-step-automations/build-a-workflow",
"destination": "/developers/browser-automations/overview"
"destination": "/browser-automations/overview"
},
{
"source": "/multi-step-automations/workflow-blocks-reference",
"destination": "/developers/browser-automations/actions-reference"
"destination": "/browser-automations/actions-reference"
},
{
"source": "/multi-step-automations/file-operations",
"destination": "/developers/browser-automations/work-with-files"
"destination": "/browser-automations/work-with-files"
},
{
"source": "/multi-step-automations/workflow-parameters",
@ -654,15 +648,15 @@
},
{
"source": "/browser-sessions/introduction",
"destination": "/developers/optimization/browser-sessions"
"destination": "/optimization/browser-sessions"
},
{
"source": "/browser-sessions/browser-profiles",
"destination": "/developers/optimization/browser-profiles"
"destination": "/optimization/browser-profiles"
},
{
"source": "/observability/overview",
"destination": "/developers/debugging/using-artifacts"
"destination": "/debugging/using-artifacts"
},
{
"source": "/integrations/make.com",
@ -674,19 +668,11 @@
},
{
"source": "/integrations/mcp-server",
"destination": "/developers/getting-started/mcp"
"destination": "/integrations/mcp"
},
{
"source": "/home/integrations/mcp-server",
"destination": "/developers/getting-started/mcp"
},
{
"source": "/integrations/mcp",
"destination": "/developers/getting-started/mcp"
},
{
"source": "/going-to-production/mcp",
"destination": "/developers/getting-started/mcp"
"destination": "/integrations/mcp"
},
{
"source": "/api-reference/api-reference/agent/run-task",
@ -827,38 +813,6 @@
{
"source": "/api-reference/api-reference/files/upload-file",
"destination": "/api-reference/files/upload-file"
},
{
"source": "/getting-started/:slug*",
"destination": "/developers/getting-started/:slug*"
},
{
"source": "/credentials/:slug*",
"destination": "/developers/credentials/:slug*"
},
{
"source": "/debugging/:slug*",
"destination": "/developers/debugging/:slug*"
},
{
"source": "/going-to-production/:slug*",
"destination": "/developers/going-to-production/:slug*"
},
{
"source": "/optimization/:slug*",
"destination": "/developers/optimization/:slug*"
},
{
"source": "/self-hosted/:slug*",
"destination": "/developers/self-hosted/:slug*"
},
{
"source": "/features/:slug*",
"destination": "/developers/features/:slug*"
},
{
"source": "/browser-automations/:slug*",
"destination": "/developers/browser-automations/:slug*"
}
]
}

View file

@ -2,7 +2,7 @@
title: Authentication & 2FA
subtitle: Log in to any site, including sites with multi-factor authentication
description: Skyvern handles logins with stored credentials, TOTP/authenticator codes, email and SMS verification, magic links, and password manager integrations with Bitwarden, 1Password, and Azure Key Vault.
slug: developers/features/authentication-and-2fa
slug: features/authentication-and-2fa
icon: key
keywords:
- authentication
@ -43,19 +43,19 @@ You'll see this in practice: run recordings, action timelines, and LLM prompts s
<CardGroup cols={2}>
<Card
title="Store credentials"
href="/developers/credentials/store-credentials"
href="/credentials/store-credentials"
>
Create passwords, cards, and secrets. Wire up Bitwarden, 1Password, Azure, or a custom vault.
</Card>
<Card
title="Handle 2FA"
href="/developers/credentials/handle-2fa"
href="/credentials/handle-2fa"
>
TOTP setup, pushed codes, polled endpoints, and magic links.
</Card>
<Card
title="Troubleshoot logins"
href="/developers/credentials/troubleshooting-login"
href="/credentials/troubleshooting-login"
>
Debug 2FA and login failures.
</Card>

View file

@ -2,7 +2,7 @@
title: Browser Sessions
subtitle: Keep a live browser open across multiple tasks and workflows
description: Skyvern browser sessions are live browser instances that persist cookies, local storage, and page state across runs. Use them for back-to-back tasks, human-in-the-loop flows, and real-time agents.
slug: developers/features/browser-sessions
slug: features/browser-sessions
icon: window-restore
keywords:
- browser sessions
@ -28,30 +28,30 @@ A Browser Session is a live browser instance that Skyvern keeps running between
## Configuration
Sessions support timeouts from 5 minutes to 24 hours (defaulting to 60 minutes), proxy locations across any of Skyvern's [21 supported countries](/developers/going-to-production/proxy-geolocation), Chrome or Edge browser types, and built-in extensions for ad-blocking and CAPTCHA solving. Every session exposes a live VNC stream.
Sessions support timeouts from 5 minutes to 24 hours (defaulting to 60 minutes), proxy locations across any of Skyvern's [21 supported countries](/going-to-production/proxy-geolocation), Chrome or Edge browser types, and built-in extensions for ad-blocking and CAPTCHA solving. Every session exposes a live VNC stream.
## Sessions vs. Profiles
Sessions are live browsers that bill while open. [Browser Profiles](/developers/optimization/browser-profiles) are saved snapshots of browser state you reuse across days or weeks. You can create a profile from a finished session to save its authenticated state for later.
Sessions are live browsers that bill while open. [Browser Profiles](/optimization/browser-profiles) are saved snapshots of browser state you reuse across days or weeks. You can create a profile from a finished session to save its authenticated state for later.
## Learn more
<CardGroup cols={2}>
<Card
title="Browser sessions guide"
href="/developers/optimization/browser-sessions"
href="/optimization/browser-sessions"
>
Create sessions, run operations through them, and close cleanly.
</Card>
<Card
title="Browser profiles"
href="/developers/optimization/browser-profiles"
href="/optimization/browser-profiles"
>
Save state to reuse across days or weeks.
</Card>
<Card
title="Connect your local browser"
href="/developers/self-hosted/browser"
href="/self-hosted/browser"
>
Use your own Chrome with its existing logins and extensions.
</Card>

View file

@ -2,7 +2,7 @@
title: CAPTCHA & Bot Bypass
subtitle: How Skyvern handles CAPTCHAs and avoids triggering anti-bot systems
description: Learn how Skyvern automatically detects and solves CAPTCHAs including reCAPTCHA, hCaptcha, and Cloudflare Turnstile, and how to reduce bot detection risk using residential proxies, browser sessions, and browser profiles.
slug: developers/features/captcha-and-bot-bypass
slug: features/captcha-and-bot-bypass
icon: shield-halved
keywords:
- CAPTCHA
@ -33,11 +33,11 @@ Every run gets these protections automatically, with no configuration needed:
Beyond fingerprinting, how you structure your automation affects whether you get flagged.
**Use residential proxies for sensitive sites.** Datacenter IPs are the single most common bot signal. Residential proxies route through real ISP addresses. Set `proxy_location="RESIDENTIAL"` or use `RESIDENTIAL_ISP` for a static IP that persists across the session. See [Proxy & Geolocation](/developers/going-to-production/proxy-geolocation).
**Use residential proxies for sensitive sites.** Datacenter IPs are the single most common bot signal. Residential proxies route through real ISP addresses. Set `proxy_location="RESIDENTIAL"` or use `RESIDENTIAL_ISP` for a static IP that persists across the session. See [Proxy & Geolocation](/going-to-production/proxy-geolocation).
**Reuse browser sessions for multi-step flows.** Creating a fresh browser for every step is suspicious. A persistent session maintains cookies, cache, and history between operations. See [Browser Sessions](/developers/optimization/browser-sessions).
**Reuse browser sessions for multi-step flows.** Creating a fresh browser for every step is suspicious. A persistent session maintains cookies, cache, and history between operations. See [Browser Sessions](/optimization/browser-sessions).
**Use browser profiles for repeat visits.** Profiles save browser state from a previous session. The site sees a known browser with familiar cookies instead of a blank slate. See [Browser Profiles](/developers/optimization/browser-profiles).
**Use browser profiles for repeat visits.** Profiles save browser state from a previous session. The site sees a known browser with familiar cookies instead of a blank slate. See [Browser Profiles](/optimization/browser-profiles).
**Add wait blocks between rapid actions.** Instant back-to-back actions can trigger behavioral detection. A short pause between steps looks more human.
@ -60,25 +60,25 @@ Automatic CAPTCHA solving is not available for self-hosted deployments. When a C
<CardGroup cols={2}>
<Card
title="Proxy & Geolocation"
href="/developers/going-to-production/proxy-geolocation"
href="/going-to-production/proxy-geolocation"
>
Route traffic through residential proxies in 21 countries.
</Card>
<Card
title="Handle 2FA"
href="/developers/credentials/handle-2fa"
href="/credentials/handle-2fa"
>
Configure TOTP, email, and SMS verification codes.
</Card>
<Card
title="Browser Sessions"
href="/developers/optimization/browser-sessions"
href="/optimization/browser-sessions"
>
Persist browser state across multiple runs.
</Card>
<Card
title="Error Handling"
href="/developers/going-to-production/error-handling"
href="/going-to-production/error-handling"
>
Map CAPTCHA and bot failures to custom error codes.
</Card>

View file

@ -2,7 +2,7 @@
title: Code Caching
subtitle: Convert successful runs into cached code for faster, deterministic replays
description: Skyvern records the actions an AI run takes and generates executable code from them. Subsequent runs execute the cached code directly, skipping LLM inference and screenshot analysis. Faster, cheaper, deterministic.
slug: developers/features/code-caching
slug: features/code-caching
icon: bolt
keywords:
- code caching
@ -48,7 +48,7 @@ Pair cached code with [scheduled workflows](/cloud/building-workflows/scheduling
<CardGroup cols={2}>
<Card
title="Cost control"
href="/developers/optimization/cost-control"
href="/optimization/cost-control"
>
Use `run_with: code` plus `max_steps` and engine tiers to manage costs.
</Card>
@ -60,7 +60,7 @@ Pair cached code with [scheduled workflows](/cloud/building-workflows/scheduling
</Card>
<Card
title="Reliability tips"
href="/developers/going-to-production/reliability-tips"
href="/going-to-production/reliability-tips"
>
Keep cached runs stable as target sites evolve.
</Card>

View file

@ -2,7 +2,7 @@
title: Proxy & GEO Targeting
subtitle: Route browser traffic through residential IPs in 21 countries
description: Skyvern routes browser traffic through residential proxies in 21 countries, with city- and state-level targeting in the US. Use it to access region-locked content, test geo-specific experiences, and reduce bot detection risk.
slug: developers/features/proxy-and-geo-targeting
slug: features/proxy-and-geo-targeting
icon: globe
keywords:
- proxy
@ -26,7 +26,7 @@ For services that require a stable IP across a session, `RESIDENTIAL_ISP` provid
## How it's applied
**Per task:** pass `proxy_location` in the run request. **Per workflow:** set a default on the workflow and override on any individual run. **Per session:** lock a proxy to a [browser session](/developers/optimization/browser-sessions) so every operation in that session shares the same IP.
**Per task:** pass `proxy_location` in the run request. **Per workflow:** set a default on the workflow and override on any individual run. **Per session:** lock a proxy to a [browser session](/optimization/browser-sessions) so every operation in that session shares the same IP.
## When to use it
@ -37,25 +37,25 @@ Region-locked pricing, inventory, or UX becomes visible when you route through t
<CardGroup cols={2}>
<Card
title="Proxy & geolocation guide"
href="/developers/going-to-production/proxy-geolocation"
href="/going-to-production/proxy-geolocation"
>
Full country list, `proxy_location` values, and `GeoTarget` examples.
</Card>
<Card
title="CAPTCHA & bot bypass"
href="/developers/features/captcha-and-bot-bypass"
href="/features/captcha-and-bot-bypass"
>
Pair residential proxies with stealth for sensitive sites.
</Card>
<Card
title="Browser sessions"
href="/developers/optimization/browser-sessions"
href="/optimization/browser-sessions"
>
Lock a proxy location across multiple operations in one session.
</Card>
<Card
title="Self-hosted proxy"
href="/developers/self-hosted/proxy"
href="/self-hosted/proxy"
>
Bring your own proxy on self-hosted deployments.
</Card>

View file

@ -2,7 +2,7 @@
title: AI Agents Quickstart
subtitle: Give your AI coding assistant full browser automation in one command
description: Give your AI coding assistant full browser control capabilities in one prommpt
slug: developers/getting-started/ai-agents-quickstart
slug: getting-started/ai-agents-quickstart
keywords:
- MCP
- Claude Desktop

View file

@ -2,7 +2,7 @@
title: Core Concepts
subtitle: The building blocks of Skyvern automations
description: Learn about tasks, workflows, browser sessions, credentials, and other building blocks that make up Skyvern automations.
slug: developers/getting-started/core-concepts
slug: getting-started/core-concepts
keywords:
- task
- workflow

View file

@ -2,7 +2,7 @@
title: What is Skyvern?
subtitle: AI-powered browser automation for any website
description: Skyvern automates browser-based workflows using LLMs and computer vision. It navigates websites it has never seen before, filling forms, extracting data, and completing multi-step tasks via a simple API.
slug: developers/getting-started/introduction
slug: getting-started/introduction
keywords:
- browser automation
- AI agent

View file

@ -2,7 +2,7 @@
title: Quickstart
subtitle: Run your first browser automation in 5 minutes
description: Launch a cloud browser, go to a webpage, and extract structured data with Python, TypeScript, or cURL in under 5 minutes.
slug: developers/getting-started/quickstart
slug: getting-started/quickstart
keywords:
- quickstart
- launch_cloud_browser
@ -126,7 +126,7 @@ curl -X POST "https://api.skyvern.com/v1/run/tasks" \
</CodeGroup>
<Info>
**Why `page.extract` is enough here.** For a one-shot read on a single page, `page.extract(prompt, schema=...)` returns the extracted data directly (a `dict` in Python, `object` in TS). For multi-step goals like *"log in, navigate to billing, download the invoice"*, use `page.agent.run_task(prompt)` instead; it runs a full AI task loop on the page and returns a [`TaskRunResponse`](/sdk-reference/tasks/run-task#returns-taskrunresponse). See [Build a Browser Automation](/developers/browser-automations/overview) for the full walkthrough.
**Why `page.extract` is enough here.** For a one-shot read on a single page, `page.extract(prompt, schema=...)` returns the extracted data directly (a `dict` in Python, `object` in TS). For multi-step goals like *"log in, navigate to billing, download the invoice"*, use `page.agent.run_task(prompt)` instead; it runs a full AI task loop on the page and returns a [`TaskRunResponse`](/sdk-reference/tasks/run-task#returns-taskrunresponse). See [Build a Browser Automation](/browser-automations/overview) for the full walkthrough.
</Info>
## Step 4: Understand the output
@ -139,7 +139,7 @@ Extracted: {'top_post_title': 'Linux kernel framework for PCIe device emulation,
```
- **`Watch live: ...`** is printed before any AI calls. Open it in another tab to watch the browser navigate and extract in real time.
- **`Extracted: {...}`** appears after `page.extract` returns. The key names come from the AI (unless you pass a `schema`, in which case they match your schema). For typed, predictable output, see [Extract Structured Data](/developers/browser-automations/extract-structured-data).
- **`Extracted: {...}`** appears after `page.extract` returns. The key names come from the AI (unless you pass a `schema`, in which case they match your schema). For typed, predictable output, see [Extract Structured Data](/browser-automations/extract-structured-data).
### If you used the cURL path
@ -308,21 +308,21 @@ If you also selected Claude Code during setup, start your local frontend dev ser
<Card
title="Build a Browser Automation"
icon="browser"
href="/developers/browser-automations/overview"
href="/browser-automations/overview"
>
The full Page/Agent/Browser walkthrough: AI actions, Playwright selectors, and agent tasks
</Card>
<Card
title="Actions Reference"
icon="list"
href="/developers/browser-automations/actions-reference"
href="/browser-automations/actions-reference"
>
Every page action and agent method with parameters and return types
</Card>
<Card
title="Extract Structured Data"
icon="database"
href="/developers/browser-automations/extract-structured-data"
href="/browser-automations/extract-structured-data"
>
Define a schema to get typed JSON output from your automations
</Card>
@ -343,7 +343,7 @@ If you also selected Claude Code during setup, start your local frontend dev ser
<Card
title="Use Webhooks"
icon="webhook"
href="/developers/going-to-production/webhooks"
href="/going-to-production/webhooks"
>
Get notified when tasks complete instead of polling
</Card>

View file

@ -2,7 +2,7 @@
title: Error Handling
subtitle: Build systems that detect, classify, and recover from failures
description: Detect, classify, and recover from task and workflow failures using run status, failure_reason, custom error_code_mapping, and validation blocks. Build programmatic error handling with retry logic and branching.
slug: developers/going-to-production/error-handling
slug: going-to-production/error-handling
keywords:
- failure_reason
- run status
@ -691,14 +691,14 @@ If `verify_login` sees a login error, the workflow terminates with `output.error
<Card
title="Reliability Tips"
icon="shield-check"
href="/developers/going-to-production/reliability-tips"
href="/going-to-production/reliability-tips"
>
Write prompts that fail less often
</Card>
<Card
title="Webhooks"
icon="webhook"
href="/developers/going-to-production/webhooks"
href="/going-to-production/webhooks"
>
Get notified when runs complete or fail
</Card>

View file

@ -2,7 +2,7 @@
title: Proxy & Geolocation
subtitle: Route browser traffic through residential proxies worldwide
description: Route Skyvern browser traffic through residential proxies in 20 countries to bypass geo-restrictions, avoid bot detection, and access region-locked content. Configure proxy_location for tasks, workflows, and browser sessions.
slug: developers/going-to-production/proxy-geolocation
slug: going-to-production/proxy-geolocation
keywords:
- proxy_location
- residential proxy
@ -725,7 +725,7 @@ curl -X POST "https://api.skyvern.com/v1/run/tasks" \
| Site still blocks requests | Bot detection beyond IP geolocation (fingerprinting, behavioral analysis) | Use `RESIDENTIAL_ISP` for static IPs, match proxy to site's region, add `wait` blocks between actions |
| Need to debug proxy issues | Isolate whether proxy is causing failures | Set `proxy_location: "NONE"` to bypass proxy entirely |
For sites with aggressive bot detection, combine residential proxies with the techniques in [CAPTCHA & Bot Bypass](/developers/features/captcha-and-bot-bypass).
For sites with aggressive bot detection, combine residential proxies with the techniques in [CAPTCHA & Bot Bypass](/features/captcha-and-bot-bypass).
Need a location that's not available? Get help in the [Skyvern Discord community](https://discord.gg/skyvern) to request new proxy pools.
@ -737,14 +737,14 @@ Need a location that's not available? Get help in the [Skyvern Discord community
<Card
title="Captcha & Bot Detection"
icon="robot"
href="/developers/features/captcha-and-bot-bypass"
href="/features/captcha-and-bot-bypass"
>
Combine proxies with anti-detection techniques
</Card>
<Card
title="Browser Sessions"
icon="window"
href="/developers/optimization/browser-sessions"
href="/optimization/browser-sessions"
>
Maintain IP consistency across multi-step tasks
</Card>

View file

@ -2,7 +2,7 @@
title: Reliability Tips
subtitle: Write robust prompts and handle edge cases
description: Write robust prompts with clear completion criteria, choose the right block type for each step, handle dynamic pages and popups, and add validation blocks to catch errors before they cascade.
slug: developers/going-to-production/reliability-tips
slug: going-to-production/reliability-tips
keywords:
- prompt engineering
- completion criteria
@ -362,7 +362,7 @@ When a run fails:
<Card
title="Error Handling"
icon="triangle-exclamation"
href="/developers/going-to-production/error-handling"
href="/going-to-production/error-handling"
>
Map errors to custom codes for programmatic handling
</Card>

View file

@ -2,7 +2,7 @@
title: Webhooks
subtitle: Get notified when tasks and workflows complete
description: Configure webhook URLs for tasks and workflows to receive notifications when runs reach terminal status. Includes payload structure, HMAC-SHA256 signature verification, failure handling, and retry mechanisms.
slug: developers/going-to-production/webhooks
slug: going-to-production/webhooks
keywords:
- webhook_url
- HMAC-SHA256
@ -230,7 +230,7 @@ User-Agent: python-httpx/0.28.1
| `run_id` | string | Unique identifier for this run |
| `task_id` | string | Same as `run_id` |
| `status` | string | `completed`, `failed`, `terminated`, `timed_out`, or `canceled` |
| `output` | object \| null | Extracted data from the task. If you configured [`error_code_mapping`](/developers/going-to-production/error-handling#step-3-use-error_code_mapping), failed runs include `output.error` with your custom error code. |
| `output` | object \| null | Extracted data from the task. If you configured [`error_code_mapping`](/going-to-production/error-handling#step-3-use-error_code_mapping), failed runs include `output.error` with your custom error code. |
| `summary` | string | AI-generated description of what was done |
| `prompt` | string | The prompt from the original request |
| `url` | string | The URL from the original request |
@ -526,14 +526,14 @@ You can pass a different `webhook_url` to send the payload to a new endpoint; us
<Card
title="Error Handling"
icon="triangle-exclamation"
href="/developers/going-to-production/error-handling"
href="/going-to-production/error-handling"
>
Handle failures and map custom error codes
</Card>
<Card
title="Reliability Tips"
icon="shield-check"
href="/developers/going-to-production/reliability-tips"
href="/going-to-production/reliability-tips"
>
Write robust prompts and add validation blocks
</Card>

View file

@ -114,7 +114,7 @@ The `--use-local-profile` flag clones cookies and saved passwords from your Chro
Always pass `--api-key` when using `--tunnel`. Without it, anyone with the ngrok URL has full browser control.
</Warning>
See the [full guide](/developers/optimization/browser-tunneling) for all options, manual tunnel setup, and security details.
See the [full guide](/optimization/browser-tunneling) for all options, manual tunnel setup, and security details.
### Workflows

View file

@ -135,7 +135,7 @@ skyvern run server
<Card
title="Quickstart"
icon="rocket"
href="/developers/getting-started/quickstart"
href="/getting-started/quickstart"
>
Get started with Skyvern
</Card>

View file

@ -121,7 +121,7 @@ Retrieve the output of a completed run.
<Card
title="Use Webhooks"
icon="webhook"
href="/developers/going-to-production/webhooks"
href="/going-to-production/webhooks"
>
Get notified when tasks complete
</Card>

View file

@ -1,3 +1,26 @@
---
title: MCP Server
subtitle: Connect AI assistants to browser automation via Model Context Protocol
description: Install and configure Skyvern's MCP server so Claude Desktop, Claude Code, Cursor, Windsurf, Codex, Hermes, OpenClaw, and other AI tools can run browser automations over OAuth or API key.
slug: going-to-production/mcp
keywords:
- MCP
- Model Context Protocol
- OAuth
- Claude Desktop
- Claude Code
- Cursor
- Windsurf
- Codex
- Hermes
- OpenClaw
- MCPorter
- AI assistant
- tools
- stdio
- streamable-http
---
The Skyvern MCP server lets AI assistants like Claude Desktop, Claude Code, Codex, Cursor, and Windsurf control a browser. Your AI can fill out forms, extract data, download files, and run multi-step workflows, all through natural language.
## What you can do

View file

@ -113,7 +113,7 @@ First, create your workflow in the [Skyvern UI](https://app.skyvern.com).
<Card
title="Use Webhooks"
icon="webhook"
href="/developers/going-to-production/webhooks"
href="/going-to-production/webhooks"
>
Get notified when tasks complete
</Card>

View file

@ -118,7 +118,7 @@ Retrieve the details of a completed run.
<Card
title="Use Webhooks"
icon="webhook"
href="/developers/going-to-production/webhooks"
href="/going-to-production/webhooks"
>
Get notified when tasks complete
</Card>

View file

@ -131,7 +131,7 @@ Retrieve the output of a completed run.
<Card
title="Use Webhooks"
icon="webhook"
href="/developers/going-to-production/webhooks"
href="/going-to-production/webhooks"
>
Get notified when tasks complete
</Card>

View file

@ -1,4 +1,4 @@
---
title: "Getting Started"
url: "/developers/getting-started/introduction"
url: "/getting-started/introduction"
---

View file

@ -2,7 +2,7 @@
title: Browser Profiles
subtitle: Save and reuse authenticated browser state across runs
description: Save browser state snapshots including cookies, localStorage, and session files as reusable profiles. Skip login steps and restore authenticated state instantly across workflow runs.
slug: developers/optimization/browser-profiles
slug: optimization/browser-profiles
keywords:
- create_browser_profile
- state snapshot
@ -224,7 +224,7 @@ done
### From a browser session
You can also create a profile from a [Browser Session](/developers/optimization/browser-sessions) that was used inside a workflow with `persist_browser_session=true`. After the workflow run completes and the session is closed, pass the session ID instead of the workflow run ID.
You can also create a profile from a [Browser Session](/optimization/browser-sessions) that was used inside a workflow with `persist_browser_session=true`. After the workflow run completes and the session is closed, pass the session ID instead of the workflow run ID.
<Warning>
Only sessions that were part of a workflow with `persist_browser_session=true` produce an archive. A session created with `create_browser_session()` alone does not archive its state. Archiving happens asynchronously after the session closes, so add retry logic.
@ -907,14 +907,14 @@ if (shouldRefreshProfile) {
<Card
title="Browser Sessions"
icon="browser"
href="/developers/optimization/browser-sessions"
href="/optimization/browser-sessions"
>
Maintain live browser state for real-time interactions
</Card>
<Card
title="Cost Control"
icon="dollar-sign"
href="/developers/optimization/cost-control"
href="/optimization/cost-control"
>
Optimize costs with max_steps and efficient prompts
</Card>

View file

@ -2,7 +2,7 @@
title: Browser Sessions
subtitle: Persist live browser state across multiple tasks and workflows
description: Create and manage live browser sessions that persist cookies, local storage, and page state between task or workflow runs. Use sessions for back-to-back tasks, human-in-the-loop approval, and real-time agents.
slug: developers/optimization/browser-sessions
slug: optimization/browser-sessions
keywords:
- create_browser_session
- persistent state
@ -83,7 +83,7 @@ curl -X POST "https://api.skyvern.com/v1/browser_sessions" \
| Parameter | Type | Description |
|-----------|------|-------------|
| `timeout` | integer | Session lifetime in minutes. Min: 5, Max: 1440 (24 hours). Default: `60` |
| `proxy_location` | string | Geographic proxy location (Cloud only). See [Proxy & Geolocation](/developers/going-to-production/proxy-geolocation) for available options |
| `proxy_location` | string | Geographic proxy location (Cloud only). See [Proxy & Geolocation](/going-to-production/proxy-geolocation) for available options |
| `browser_type` | string | Browser type: `chrome` or `msedge` |
| `extensions` | array | Extensions to install: `ad-blocker`, `captcha-solver` |
@ -683,7 +683,7 @@ curl -s -X POST "https://api.skyvern.com/v1/browser_sessions" \
## Sessions vs Profiles
Skyvern also offers [Browser Profiles](/developers/optimization/browser-profiles), saved snapshots of browser state (cookies, storage, session files) that you can reuse across days or weeks. Choose based on your use case:
Skyvern also offers [Browser Profiles](/optimization/browser-profiles), saved snapshots of browser state (cookies, storage, session files) that you can reuse across days or weeks. Choose based on your use case:
| Aspect | Browser Session | Browser Profile |
|--------|----------------|-----------------|
@ -694,7 +694,7 @@ Skyvern also offers [Browser Profiles](/developers/optimization/browser-profiles
| **Best for** | Back-to-back tasks, human-in-the-loop, real-time agents | Repeated logins, scheduled workflows, shared auth state |
<Tip>
You can create a [Browser Profile](/developers/optimization/browser-profiles) from a completed session to save its authenticated state for future reuse.
You can create a [Browser Profile](/optimization/browser-profiles) from a completed session to save its authenticated state for future reuse.
</Tip>
---
@ -705,21 +705,21 @@ You can create a [Browser Profile](/developers/optimization/browser-profiles) fr
<Card
title="Connect Your Local Browser"
icon="laptop"
href="/developers/optimization/browser-tunneling"
href="/optimization/browser-tunneling"
>
Let Skyvern Cloud use your local browser with your existing logins
</Card>
<Card
title="Browser Profiles"
icon="floppy-disk"
href="/developers/optimization/browser-profiles"
href="/optimization/browser-profiles"
>
Save session state for reuse across days
</Card>
<Card
title="Cost Control"
icon="dollar-sign"
href="/developers/optimization/cost-control"
href="/optimization/cost-control"
>
Optimize costs with max_steps and efficient prompts
</Card>

View file

@ -2,7 +2,7 @@
title: Connect Skyvern to Your Local Browser
subtitle: Run automations using your existing cookies, logins, and extensions
description: Use skyvern browser serve to let Skyvern Cloud control a Chrome browser on your local machine, reusing your existing cookies, sessions, extensions, and saved passwords through a secure tunnel.
slug: developers/optimization/browser-tunneling
slug: optimization/browser-tunneling
keywords:
- browser session
- task
@ -208,9 +208,9 @@ The built-in API key provides basic protection. For additional security such as
| Approach | When to use |
|----------|-------------|
| **Connect to your local browser** (`skyvern browser serve`) | You want Skyvern Cloud to use your local browser with your existing sessions |
| **[Browser Sessions](/developers/optimization/browser-sessions)** | You want Skyvern Cloud to manage the browser entirely in the cloud |
| **[Browser Profiles](/developers/optimization/browser-profiles)** | You want to save and reuse cookies/storage state across cloud sessions |
| **[CDP Connect](/developers/self-hosted/browser#cdp-connect-external-chrome)** (self-hosted) | You're running Skyvern locally and want to connect to an existing Chrome instance |
| **[Browser Sessions](/optimization/browser-sessions)** | You want Skyvern Cloud to manage the browser entirely in the cloud |
| **[Browser Profiles](/optimization/browser-profiles)** | You want to save and reuse cookies/storage state across cloud sessions |
| **[CDP Connect](/self-hosted/browser#cdp-connect-external-chrome)** (self-hosted) | You're running Skyvern locally and want to connect to an existing Chrome instance |
---
@ -258,10 +258,10 @@ The built-in API key provides basic protection. For additional security such as
## Next steps
<CardGroup cols={2}>
<Card title="Browser Sessions" icon="window" href="/developers/optimization/browser-sessions">
<Card title="Browser Sessions" icon="window" href="/optimization/browser-sessions">
Use cloud-managed browser sessions for multi-step tasks
</Card>
<Card title="Browser Profiles" icon="floppy-disk" href="/developers/optimization/browser-profiles">
<Card title="Browser Profiles" icon="floppy-disk" href="/optimization/browser-profiles">
Save and reuse authenticated browser state
</Card>
</CardGroup>

View file

@ -2,7 +2,7 @@
title: Cost Control
subtitle: Limit steps and optimize prompts to manage costs
description: Control Skyvern costs using max_steps limits, code generation for repeatable tasks, cheaper engine tiers, and prompt optimization techniques to reduce step count and credit usage.
slug: developers/optimization/cost-control
slug: optimization/cost-control
keywords:
- max_steps
- credits
@ -258,7 +258,7 @@ curl -X POST "https://api.skyvern.com/v1/run/tasks" \
```
</CodeGroup>
For self-hosted deployments, you can also swap the underlying LLM to a cheaper model (e.g., Gemini 2.5 Flash instead of a pro-tier model) via the `LLM_KEY` environment variable. See [LLM configuration](/developers/self-hosted/llm-configuration) for details.
For self-hosted deployments, you can also swap the underlying LLM to a cheaper model (e.g., Gemini 2.5 Flash instead of a pro-tier model) via the `LLM_KEY` environment variable. See [LLM configuration](/self-hosted/llm-configuration) for details.
---
@ -270,7 +270,7 @@ Small prompt changes can cut step count significantly.
- **Avoid open-ended exploration.** Prompts like "find interesting data" or "look around" cause the agent to wander.
- **Use `data_extraction_schema`** to constrain what fields the AI extracts. This prevents it from spending steps parsing irrelevant content.
- **Provide `url`** to start on the correct page instead of making the agent search for it.
- **Use [browser profiles](/developers/optimization/browser-profiles)** to skip login steps on repeated runs.
- **Use [browser profiles](/optimization/browser-profiles)** to skip login steps on repeated runs.
---
@ -287,14 +287,14 @@ Small prompt changes can cut step count significantly.
<Card
title="Browser Sessions"
icon="browser"
href="/developers/optimization/browser-sessions"
href="/optimization/browser-sessions"
>
Maintain live browser state between calls
</Card>
<Card
title="Browser Profiles"
icon="floppy-disk"
href="/developers/optimization/browser-profiles"
href="/optimization/browser-profiles"
>
Save authenticated state for reuse across days
</Card>

View file

@ -5,7 +5,7 @@ slug: sdk-reference/browser-profiles/create-browser-profile
A browser profile is a snapshot of browser state: cookies, local storage, session data. Create a profile from a completed run, then load it into future workflow runs to skip login and setup steps.
For conceptual background, see [Browser Profiles](/developers/optimization/browser-profiles).
For conceptual background, see [Browser Profiles](/optimization/browser-profiles).
<Note>
Python uses `snake_case` (e.g., `create_browser_profile`); TypeScript uses `camelCase` (e.g., `createBrowserProfile`). Parameter tables show Python names. TypeScript names are the camelCase equivalents.

View file

@ -5,7 +5,7 @@ slug: sdk-reference/browser-sessions/create-browser-session
A browser session is a persistent browser instance that stays alive between API calls. Use sessions to chain multiple tasks in the same browser without losing cookies, local storage, or login state.
For conceptual background, see [Browser Sessions](/developers/optimization/browser-sessions).
For conceptual background, see [Browser Sessions](/optimization/browser-sessions).
<Note>
Python uses `snake_case` (e.g., `create_browser_session`); TypeScript uses `camelCase` (e.g., `createBrowserSession`). Parameter tables show Python names. TypeScript names are the camelCase equivalents.

View file

@ -49,7 +49,7 @@ console.log(result.output);
| `max_steps` | `int` | No | `None` | Cap the number of AI steps to limit cost. Run terminates with `timed_out` if hit. |
| `data_extraction_schema` | `dict \| str` | No | `None` | JSON schema or Pydantic model name constraining the output shape. |
| `proxy_location` | `ProxyLocation` | No | `None` | Route the browser through a geographic proxy. |
| `browser_session_id` | `str` | No | `None` | Run inside an existing [browser session](/developers/optimization/browser-sessions). |
| `browser_session_id` | `str` | No | `None` | Run inside an existing [browser session](/optimization/browser-sessions). |
| `publish_workflow` | `bool` | No | `False` | Save the generated code as a reusable workflow. Only works with `skyvern_v2`. |
| `webhook_url` | `str` | No | `None` | URL to receive a POST when the run finishes. |
| `error_code_mapping` | `dict[str, str]` | No | `None` | Map custom error codes to failure reasons. |
@ -281,7 +281,7 @@ console.log(run.output);
</CodeGroup>
<Tip>
For production, prefer `wait_for_completion=True` / `waitForCompletion: true` or [webhooks](/developers/going-to-production/webhooks) over manual polling.
For production, prefer `wait_for_completion=True` / `waitForCompletion: true` or [webhooks](/going-to-production/webhooks) over manual polling.
</Tip>
---

View file

@ -43,8 +43,8 @@ console.log(result.output);
| `timeout` | `float` | No | `1800` | Max wait time in seconds when `wait_for_completion=True`. |
| `run_with` | `str` | No | `None` | Force execution mode: `"code"` (use cached Playwright code) or `"agent"` (use AI). |
| `ai_fallback` | `bool` | No | `None` | Fall back to AI if the cached code fails. |
| `browser_session_id` | `str` | No | `None` | Run inside an existing [browser session](/developers/optimization/browser-sessions). |
| `browser_profile_id` | `str` | No | `None` | Load a [browser profile](/developers/optimization/browser-profiles) (cookies, storage) into the session. |
| `browser_session_id` | `str` | No | `None` | Run inside an existing [browser session](/optimization/browser-sessions). |
| `browser_profile_id` | `str` | No | `None` | Load a [browser profile](/optimization/browser-profiles) (cookies, storage) into the session. |
| `proxy_location` | `ProxyLocation` | No | `None` | Route the browser through a geographic proxy. |
| `max_steps_override` | `int` | No | `None` | Cap total AI steps across all blocks. |
| `webhook_url` | `str` | No | `None` | URL to receive a POST when the run finishes. |

View file

@ -2,7 +2,7 @@
title: Browser Configuration
subtitle: Configure browser modes, display settings, and external Chrome connections
description: Configure Skyvern's browser modes including headful, headless, local Chrome, and CDP connect. Set display resolution, viewport size, and connect to external Chrome instances for self-hosted deployments.
slug: developers/self-hosted/browser
slug: self-hosted/browser
keywords:
- headless
- headful
@ -323,7 +323,7 @@ Add more RAM to your server and increase `MAX_STEPS_PER_RUN` and `BROWSER_MAX_PA
### Option 2: Horizontal scaling
Deploy multiple Skyvern instances behind a load balancer. Each instance runs its own browser. See [Kubernetes Deployment](/developers/self-hosted/kubernetes) for orchestrated scaling.
Deploy multiple Skyvern instances behind a load balancer. Each instance runs its own browser. See [Kubernetes Deployment](/self-hosted/kubernetes) for orchestrated scaling.
### Option 3: External browser pool
@ -339,10 +339,10 @@ BROWSER_REMOTE_DEBUGGING_URL=http://browserless:3000/
## Next steps
<CardGroup cols={2}>
<Card title="Proxy Setup" icon="shield" href="/developers/self-hosted/proxy">
<Card title="Proxy Setup" icon="shield" href="/self-hosted/proxy">
Configure proxies to avoid bot detection
</Card>
<Card title="Storage Configuration" icon="hard-drive" href="/developers/self-hosted/storage">
<Card title="Storage Configuration" icon="hard-drive" href="/self-hosted/storage">
Store recordings and artifacts in S3 or Azure Blob
</Card>
</CardGroup>

View file

@ -2,7 +2,7 @@
title: Docker Setup
subtitle: Get Skyvern running in 10 minutes with Docker Compose
description: Deploy Skyvern using Docker Compose with the API server, embedded browser, PostgreSQL database, and web UI. Includes LLM provider configuration and first-run setup.
slug: developers/self-hosted/docker
slug: self-hosted/docker
keywords:
- Docker Compose
- docker-compose.yml
@ -46,7 +46,7 @@ OPENAI_API_KEY=sk-your-api-key-here
LLM_KEY=OPENAI_GPT4O
```
For other providers, see [LLM Configuration](/developers/self-hosted/llm-configuration).
For other providers, see [LLM Configuration](/self-hosted/llm-configuration).
### 3. Configure the frontend
@ -172,7 +172,7 @@ The `.env` file controls the Skyvern server. Here are the most important variabl
### LLM Configuration
Configure at least one LLM provider. See [LLM Configuration](/developers/self-hosted/llm-configuration) for all providers.
Configure at least one LLM provider. See [LLM Configuration](/self-hosted/llm-configuration) for all providers.
```bash
# OpenAI
@ -384,16 +384,16 @@ The page content is too large for the LLM. Try:
## Next steps
<CardGroup cols={2}>
<Card title="LLM Configuration" icon="microchip" href="/developers/self-hosted/llm-configuration">
<Card title="LLM Configuration" icon="microchip" href="/self-hosted/llm-configuration">
Configure OpenAI, Anthropic, Azure, Ollama, and other providers
</Card>
<Card title="Browser Configuration" icon="window" href="/developers/self-hosted/browser">
<Card title="Browser Configuration" icon="window" href="/self-hosted/browser">
Customize browser settings, locales, and connect to external Chrome
</Card>
<Card title="Storage Configuration" icon="hard-drive" href="/developers/self-hosted/storage">
<Card title="Storage Configuration" icon="hard-drive" href="/self-hosted/storage">
Store artifacts in S3 or Azure Blob instead of local disk
</Card>
<Card title="Proxy Setup" icon="shield" href="/developers/self-hosted/proxy">
<Card title="Proxy Setup" icon="shield" href="/self-hosted/proxy">
Configure proxies to avoid bot detection
</Card>
</CardGroup>

View file

@ -2,7 +2,7 @@
title: Kubernetes Deployment
subtitle: Deploy Skyvern at scale with Kubernetes manifests
description: Deploy Skyvern on Kubernetes for production environments with horizontal scaling and high availability. Includes manifests for the API server, frontend, PostgreSQL, and ingress configuration.
slug: developers/self-hosted/kubernetes
slug: self-hosted/kubernetes
keywords:
- Kubernetes
- Helm
@ -94,7 +94,7 @@ stringData:
LOG_LEVEL: "INFO"
```
For other LLM providers, see [LLM Configuration](/developers/self-hosted/llm-configuration).
For other LLM providers, see [LLM Configuration](/self-hosted/llm-configuration).
### 3. Configure frontend secrets
@ -292,7 +292,7 @@ spec:
### Using S3 or Azure Blob
For cloud storage, configure the backend environment variables instead of mounting volumes. See [Storage Configuration](/developers/self-hosted/storage).
For cloud storage, configure the backend environment variables instead of mounting volumes. See [Storage Configuration](/self-hosted/storage).
---
@ -442,10 +442,10 @@ rm -rf /data/artifacts /data/videos /data/har /data/log /app/.streamlit
## Next steps
<CardGroup cols={2}>
<Card title="Storage Configuration" icon="hard-drive" href="/developers/self-hosted/storage">
<Card title="Storage Configuration" icon="hard-drive" href="/self-hosted/storage">
Configure S3 or Azure Blob for artifact storage
</Card>
<Card title="LLM Configuration" icon="microchip" href="/developers/self-hosted/llm-configuration">
<Card title="LLM Configuration" icon="microchip" href="/self-hosted/llm-configuration">
Configure additional LLM providers
</Card>
</CardGroup>

View file

@ -2,7 +2,7 @@
title: LLM Configuration
subtitle: Connect your preferred language model provider
description: Configure LLM providers for self-hosted Skyvern including OpenAI, Anthropic, Azure OpenAI, Google Gemini, AWS Bedrock, Ollama, and OpenAI-compatible endpoints via LiteLLM.
slug: developers/self-hosted/llm-configuration
slug: self-hosted/llm-configuration
keywords:
- OpenAI
- Anthropic
@ -601,10 +601,10 @@ LLM calls typically take 2-10 seconds. Longer times may indicate:
## Next steps
<CardGroup cols={2}>
<Card title="Browser Configuration" icon="window" href="/developers/self-hosted/browser">
<Card title="Browser Configuration" icon="window" href="/self-hosted/browser">
Configure browser modes, locales, and display settings
</Card>
<Card title="Docker Setup" icon="docker" href="/developers/self-hosted/docker">
<Card title="Docker Setup" icon="docker" href="/self-hosted/docker">
Return to the main Docker setup guide
</Card>
</CardGroup>

View file

@ -2,7 +2,7 @@
title: Self-Hosted Overview
subtitle: Run Skyvern on your own infrastructure
description: Deploy Skyvern on your own infrastructure with Docker or Kubernetes. Configure LLM providers, browsers, proxies, and storage.
slug: developers/self-hosted/overview
slug: self-hosted/overview
keywords:
- self-hosted
- on-premise
@ -98,10 +98,10 @@ Most teams start with Docker Compose. It's the fastest path to a working deploym
## Next steps
<CardGroup cols={2}>
<Card title="Docker Setup" icon="docker" href="/developers/self-hosted/docker">
<Card title="Docker Setup" icon="docker" href="/self-hosted/docker">
Get Skyvern running in 10 minutes with Docker Compose
</Card>
<Card title="Kubernetes Deployment" icon="dharmachakra" href="/developers/self-hosted/kubernetes">
<Card title="Kubernetes Deployment" icon="dharmachakra" href="/self-hosted/kubernetes">
Deploy to production with Kubernetes manifests
</Card>
</CardGroup>

View file

@ -2,7 +2,7 @@
title: Proxy Setup
subtitle: Configure proxies to avoid bot detection
description: Configure residential, ISP, or datacenter proxies for self-hosted Skyvern deployments to avoid bot detection, bypass geo-restrictions, and prevent rate limiting on target websites.
slug: developers/self-hosted/proxy
slug: self-hosted/proxy
keywords:
- residential proxy
- ISP proxy
@ -236,10 +236,10 @@ Your browser traffic will originate directly from your server's IP. This works w
## Next steps
<CardGroup cols={2}>
<Card title="Storage Configuration" icon="hard-drive" href="/developers/self-hosted/storage">
<Card title="Storage Configuration" icon="hard-drive" href="/self-hosted/storage">
Store recordings and artifacts in S3 or Azure Blob
</Card>
<Card title="Kubernetes Deployment" icon="dharmachakra" href="/developers/self-hosted/kubernetes">
<Card title="Kubernetes Deployment" icon="dharmachakra" href="/self-hosted/kubernetes">
Deploy Skyvern at scale with Kubernetes
</Card>
</CardGroup>

View file

@ -2,7 +2,7 @@
title: Storage Configuration
subtitle: Configure where Skyvern stores artifacts and recordings
description: Configure Skyvern artifact storage using local filesystem, AWS S3, or Azure Blob Storage. Covers screenshots, browser recordings, HAR files, and extracted data storage for self-hosted deployments.
slug: developers/self-hosted/storage
slug: self-hosted/storage
keywords:
- AWS S3
- Azure Blob Storage
@ -355,10 +355,10 @@ Use lifecycle policies to automatically delete old objects:
## Next steps
<CardGroup cols={2}>
<Card title="Docker Setup" icon="docker" href="/developers/self-hosted/docker">
<Card title="Docker Setup" icon="docker" href="/self-hosted/docker">
Return to the Docker setup guide
</Card>
<Card title="Kubernetes Deployment" icon="dharmachakra" href="/developers/self-hosted/kubernetes">
<Card title="Kubernetes Deployment" icon="dharmachakra" href="/self-hosted/kubernetes">
Deploy Skyvern at scale
</Card>
</CardGroup>

View file

@ -74,7 +74,7 @@ Skyvern lets AI coding assistants (Claude Code, Cursor, Windsurf, Codex) control
**Copy the prompt below** into your AI coding agent and you'll have a running automation in minutes.
<Note>
Looking to self-host instead? See the [local installation guide](/developers/getting-started/quickstart) for full setup instructions.
Looking to self-host instead? See the [local installation guide](/getting-started/quickstart) for full setup instructions.
</Note>
## 1. Get your API key
@ -321,7 +321,7 @@ x-api-key = "YOUR_SKYVERN_API_KEY"
<Card
title="Build a Browser Automation"
icon="browser"
href="/developers/browser-automations/overview"
href="/browser-automations/overview"
>
The full Page/Agent/Browser walkthrough
</Card>
@ -335,7 +335,7 @@ x-api-key = "YOUR_SKYVERN_API_KEY"
<Card
title="Full MCP Reference"
icon="server"
href="/developers/getting-started/mcp"
href="/integrations/mcp"
>
All tools, config options, local mode, and troubleshooting
</Card>

View file

@ -107,7 +107,7 @@ await browser.close()
Agents are useful when you want to mix precise Playwright control with open-ended AI goals. Log in with a direct call, then hand off "find and download the invoice" to the agent, then take back control to process the file.
<Note>
Full method reference: [Page](/sdk-reference/browser-automation/act), [Agent](/sdk-reference/browser-automation/agent-run-task), [Browser](/sdk-reference/browser-automation/launch-cloud-browser). Developer guide: [Multi-Step Automations](/developers/browser-automations/overview).
Full method reference: [Page](/sdk-reference/browser-automation/act), [Agent](/sdk-reference/browser-automation/agent-run-task), [Browser](/sdk-reference/browser-automation/launch-cloud-browser). Developer guide: [Multi-Step Automations](/browser-automations/overview).
</Note>
## Workflows
@ -277,7 +277,7 @@ data = await page.extract("Extract the monthly report data")
await browser.close()
```
See [Browser Sessions](/developers/optimization/browser-sessions) for details.
See [Browser Sessions](/optimization/browser-sessions) for details.
## Artifacts
@ -334,7 +334,7 @@ result = await skyvern.run_task(
</Card>
<Card
title="Build with the API"
href="/developers/getting-started/quickstart"
href="/getting-started/quickstart"
>
Integrate Skyvern into your product with Python, TypeScript, or REST.
</Card>
@ -343,13 +343,13 @@ result = await skyvern.run_task(
<CardGroup cols={2}>
<Card
title="AI Agents Quickstart"
href="/developers/getting-started/ai-agents-quickstart"
href="/getting-started/ai-agents-quickstart"
>
Give Claude Code, Cursor, or Windsurf browser automation via MCP.
</Card>
<Card
title="Self-host Skyvern"
href="/developers/self-hosted/overview"
href="/self-hosted/overview"
>
Deploy on your own infrastructure with your own LLM keys.
</Card>

View file

@ -58,6 +58,6 @@ Most browser automation breaks down at authentication, CAPTCHAs, or dynamic cont
Now that you understand how Skyvern works under the hood, learn the eight building blocks you'll use to create any automation.
<Card title="Core Concepts →" icon="book-open" href="/developers/getting-started/core-concepts">
<Card title="Core Concepts →" icon="book-open" href="/getting-started/core-concepts">
Tasks, workflows, blocks, runs, credentials, browser sessions, engines: everything you need to know before you start building.
</Card>

View file

@ -537,26 +537,79 @@ class WorkflowService:
ordered = [by_id[aid] for aid in artifact_ids if aid in by_id]
return _file_infos_from_download_artifacts(ordered)
async def _refresh_output_screenshot_urls(
async def _file_infos_for_workflow_run_filtered_by_filenames(
self,
workflow_run_id: str,
organization_id: str,
filenames: set[str],
) -> list[FileInfo]:
"""Look up DOWNLOAD artifact rows for the workflow run and filter to
the given filename set.
Used as a backwards-compat fallback for block-output snapshots that
were persisted without ``downloaded_file_artifact_ids`` typically
because the block's ``get_downloaded_files`` ran before
``save_downloaded_files`` finished creating the artifact rows. We
match by filename so a multi-block run doesn't merge sibling blocks'
downloads into one another's snapshots.
Filenames are matched case-sensitively against ``Artifact.uri``'s
basename, mirroring how ``_file_infos_from_download_artifacts``
derives ``filename`` from the URI.
"""
if not workflow_run_id or not organization_id or not filenames:
return []
try:
artifacts = await app.DATABASE.artifacts.list_artifacts_for_run_by_type(
run_id=workflow_run_id,
organization_id=organization_id,
artifact_type=ArtifactType.DOWNLOAD,
)
except Exception:
LOG.warning(
"Failed to refresh block-output downloaded_files via run-id lookup",
workflow_run_id=workflow_run_id,
organization_id=organization_id,
exc_info=True,
)
return []
if not artifacts:
return []
matched: list[Artifact] = []
seen: set[str] = set()
for artifact in artifacts:
basename = artifact.uri.rsplit("/", 1)[-1] if artifact.uri else ""
if basename in filenames and basename not in seen:
matched.append(artifact)
seen.add(basename)
return _file_infos_from_download_artifacts(matched)
async def _refresh_output_urls(
self,
value: Any,
organization_id: str | None,
workflow_run_id: str,
) -> Any:
"""
Recursively walk through output values and generate presigned URLs for screenshots.
"""Recursively refresh URL fields inside persisted block-output snapshots.
TaskOutput dicts stored in workflow_run_output_parameters contain artifact IDs.
This method finds any TaskOutput-like dicts and generates fresh presigned URLs
from the stored artifact IDs.
``TaskOutput`` dicts stored in ``workflow_run_output_parameters`` carry
URLs that were minted at execution time and may now be stale: legacy
S3 presigned URLs whose signature has expired, or short signed
``/v1/artifacts/{id}/content`` URLs whose ``expiry`` has passed. This
method finds any TaskOutput-like dict and rebuilds:
For backwards compatibility with old data that stored URLs directly (now expired),
we also check for task_id and regenerate URLs using the task_id lookup.
- ``task_screenshots`` / ``workflow_screenshots`` from the stored
screenshot artifact IDs (or ``task_id`` lookup for legacy snapshots
that pre-date the artifact-ID format).
- ``downloaded_files`` / ``downloaded_file_urls`` from
``downloaded_file_artifact_ids``, or when those IDs are missing
(race with ``save_downloaded_files`` at block completion) by
looking up the run's DOWNLOAD artifact rows and matching by
basename.
Also refreshes ``downloaded_files`` / ``downloaded_file_urls`` from
``downloaded_file_artifact_ids`` so block outputs return short signed
``/v1/artifacts/{id}/content`` URLs even when the URL captured at
execution time was a legacy presigned S3 URL.
End result: every URL in the response is a freshly minted short
signed ``/v1/artifacts/{id}/content`` URL, regardless of what was
captured at execution time.
"""
if isinstance(value, dict):
# Check if this looks like a TaskOutput with screenshot artifact IDs (new format)
@ -584,6 +637,30 @@ class WorkflowService:
if refreshed:
value["downloaded_files"] = [fi.model_dump(mode="json") for fi in refreshed]
value["downloaded_file_urls"] = [fi.url for fi in refreshed]
elif value.get("downloaded_files") and organization_id:
# Backwards compatibility / race fallback: the snapshot has
# ``downloaded_files`` but no ``downloaded_file_artifact_ids``.
# This happens when the block ran the artifact-first read in
# ``get_downloaded_files`` BEFORE save_downloaded_files
# finished creating the artifact rows (or before this PR
# was deployed). Re-query the run's current DOWNLOAD rows
# and match by filename so we don't pick up downloads from
# sibling blocks in a multi-block run.
stored_filenames: set[str] = set()
for fi in value["downloaded_files"]:
if isinstance(fi, dict):
filename = fi.get("filename")
if isinstance(filename, str) and filename:
stored_filenames.add(filename)
if stored_filenames:
refreshed = await self._file_infos_for_workflow_run_filtered_by_filenames(
workflow_run_id=workflow_run_id,
organization_id=organization_id,
filenames=stored_filenames,
)
if refreshed:
value["downloaded_files"] = [fi.model_dump(mode="json") for fi in refreshed]
value["downloaded_file_urls"] = [fi.url for fi in refreshed]
elif has_old_format:
# Old format (backwards compat): regenerate URLs using task_id lookup
task_id = value.get("task_id")
@ -600,11 +677,11 @@ class WorkflowService:
else:
# Recurse into nested dicts
for k, v in value.items():
value[k] = await self._refresh_output_screenshot_urls(v, organization_id, workflow_run_id)
value[k] = await self._refresh_output_urls(v, organization_id, workflow_run_id)
elif isinstance(value, list):
# Recurse into list items
for i, item in enumerate(value):
value[i] = await self._refresh_output_screenshot_urls(item, organization_id, workflow_run_id)
value[i] = await self._refresh_output_urls(item, organization_id, workflow_run_id)
return value
async def _validate_credential_id(self, credential_id: str, organization: Organization) -> None:
@ -4812,7 +4889,7 @@ class WorkflowService:
extracted_information.extend(WorkflowService._collect_extracted_information(output.value))
outputs[EXTRACTED_INFORMATION_KEY] = extracted_information
# Refresh any expired presigned screenshot URLs in the outputs
outputs = await self._refresh_output_screenshot_urls(
outputs = await self._refresh_output_urls(
outputs, organization_id=organization_id, workflow_run_id=workflow_run_id
)

View file

@ -146,7 +146,7 @@ async def test_refresh_rebuilds_downloaded_files_from_artifact_ids():
),
):
service = WorkflowService()
refreshed = await service._refresh_output_screenshot_urls(
refreshed = await service._refresh_output_urls(
persisted_block_output, organization_id="o_1", workflow_run_id="wr_1"
)
@ -191,7 +191,7 @@ async def test_refresh_leaves_legacy_outputs_untouched():
mock_get,
):
service = WorkflowService()
refreshed = await service._refresh_output_screenshot_urls(
refreshed = await service._refresh_output_urls(
persisted_block_output, organization_id="o_1", workflow_run_id="wr_1"
)
@ -228,9 +228,182 @@ async def test_refresh_handles_missing_artifact_rows():
new=AsyncMock(return_value=[]),
):
service = WorkflowService()
refreshed = await service._refresh_output_screenshot_urls(
refreshed = await service._refresh_output_urls(
persisted_block_output, organization_id="o_1", workflow_run_id="wr_1"
)
# Falls back to whatever URL was already stored; doesn't blank out.
assert refreshed["downloaded_files"][0]["url"] == "https://skyvern-uploads.s3.amazonaws.com/.../old.pdf?sig=x"
@pytest.mark.asyncio
async def test_refresh_falls_back_to_workflow_run_lookup_when_artifact_ids_missing():
"""Race / pre-#10580 fallback: snapshot has ``downloaded_files`` with stale
presigned URLs but ``downloaded_file_artifact_ids`` is null/missing
(because at block-completion time the artifact rows hadn't been created
yet). Refresh must look up by workflow_run_id and match by filename so a
multi-block run doesn't merge sibling blocks' downloads."""
from skyvern.forge.sdk.artifact.models import Artifact, ArtifactType
from skyvern.forge.sdk.workflow.service import WorkflowService
persisted_block_output = {
"task_id": "tsk_1",
"task_screenshot_artifact_ids": [],
"workflow_screenshot_artifact_ids": [],
# No downloaded_file_artifact_ids at all — the bug case from staging.
"downloaded_file_artifact_ids": None,
"downloaded_files": [
{
"url": "https://skyvern-uploads.s3.amazonaws.com/.../mybook.zip?sig=stale",
"checksum": "sha-1",
"filename": "mybook.zip",
"modified_at": None,
"artifact_id": None,
}
],
"downloaded_file_urls": [
"https://skyvern-uploads.s3.amazonaws.com/.../mybook.zip?sig=stale",
],
}
matching_artifact = Artifact(
artifact_id="a_recovered",
artifact_type=ArtifactType.DOWNLOAD,
uri="s3://skyvern-uploads/downloads/staging/o_1/wr_1/mybook.zip",
organization_id="o_1",
run_id="wr_1",
checksum="sha-1",
created_at="2026-04-26T00:00:00Z",
modified_at="2026-04-26T00:00:00Z",
)
sibling_artifact = Artifact(
artifact_id="a_sibling",
artifact_type=ArtifactType.DOWNLOAD,
uri="s3://skyvern-uploads/downloads/staging/o_1/wr_1/other-block-file.zip",
organization_id="o_1",
run_id="wr_1",
checksum="sha-2",
created_at="2026-04-26T00:00:01Z",
modified_at="2026-04-26T00:00:01Z",
)
fresh_file_info = FileInfo(
url="https://api.skyvern.com/v1/artifacts/a_recovered/content?sig=fresh",
checksum="sha-1",
filename="mybook.zip",
modified_at=matching_artifact.created_at,
artifact_id="a_recovered",
)
with (
patch(
"skyvern.forge.sdk.workflow.service.app.DATABASE.artifacts.list_artifacts_for_run_by_type",
new=AsyncMock(return_value=[matching_artifact, sibling_artifact]),
),
# Patch the helper at the call site rather than the original symbol —
# service.py imports the symbol once at module load.
patch(
"skyvern.forge.sdk.workflow.service._file_infos_from_download_artifacts",
return_value=[fresh_file_info],
),
):
service = WorkflowService()
refreshed = await service._refresh_output_urls(
persisted_block_output, organization_id="o_1", workflow_run_id="wr_1"
)
assert len(refreshed["downloaded_files"]) == 1
assert refreshed["downloaded_files"][0]["url"].startswith(
"https://api.skyvern.com/v1/artifacts/a_recovered/content"
)
assert refreshed["downloaded_file_urls"] == ["https://api.skyvern.com/v1/artifacts/a_recovered/content?sig=fresh"]
# Sibling artifact must NOT leak in — match was filtered to mybook.zip only.
assert refreshed["downloaded_files"][0]["filename"] == "mybook.zip"
@pytest.mark.asyncio
async def test_refresh_fallback_skips_when_no_filename():
"""Snapshot has downloaded_files but each entry lacks filename.
No match key don't lookup; leave snapshot untouched."""
from skyvern.forge.sdk.workflow.service import WorkflowService
persisted_block_output = {
"task_id": "tsk_1",
"task_screenshot_artifact_ids": [],
"workflow_screenshot_artifact_ids": [],
"downloaded_file_artifact_ids": None,
"downloaded_files": [
{
"url": "https://example.com/x",
"checksum": None,
"filename": None,
"modified_at": None,
"artifact_id": None,
}
],
"downloaded_file_urls": ["https://example.com/x"],
}
mock_list = AsyncMock() # must NOT be called
with patch(
"skyvern.forge.sdk.workflow.service.app.DATABASE.artifacts.list_artifacts_for_run_by_type",
mock_list,
):
service = WorkflowService()
refreshed = await service._refresh_output_urls(
persisted_block_output, organization_id="o_1", workflow_run_id="wr_1"
)
assert refreshed["downloaded_files"][0]["url"] == "https://example.com/x"
mock_list.assert_not_awaited()
@pytest.mark.asyncio
async def test_refresh_fallback_skips_when_run_lookup_finds_no_match():
"""Filename in snapshot doesn't match any current run artifact (e.g.,
legacy run that pre-dates artifact rows entirely). Leave snapshot untouched
rather than blanking the URL."""
from skyvern.forge.sdk.artifact.models import Artifact, ArtifactType
from skyvern.forge.sdk.workflow.service import WorkflowService
persisted_block_output = {
"task_id": "tsk_1",
"task_screenshot_artifact_ids": [],
"workflow_screenshot_artifact_ids": [],
"downloaded_file_artifact_ids": None,
"downloaded_files": [
{
"url": "https://skyvern-uploads.s3.amazonaws.com/.../legacy.zip?sig=x",
"checksum": "sha-1",
"filename": "legacy.zip",
"modified_at": None,
"artifact_id": None,
}
],
"downloaded_file_urls": [
"https://skyvern-uploads.s3.amazonaws.com/.../legacy.zip?sig=x",
],
}
different_artifact = Artifact(
artifact_id="a_other",
artifact_type=ArtifactType.DOWNLOAD,
uri="s3://skyvern-uploads/downloads/staging/o_1/wr_1/different.zip",
organization_id="o_1",
run_id="wr_1",
checksum="sha-9",
created_at="2026-04-26T00:00:00Z",
modified_at="2026-04-26T00:00:00Z",
)
with patch(
"skyvern.forge.sdk.workflow.service.app.DATABASE.artifacts.list_artifacts_for_run_by_type",
new=AsyncMock(return_value=[different_artifact]),
):
service = WorkflowService()
refreshed = await service._refresh_output_urls(
persisted_block_output, organization_id="o_1", workflow_run_id="wr_1"
)
# No match → stored URL preserved.
assert refreshed["downloaded_files"][0]["url"] == "https://skyvern-uploads.s3.amazonaws.com/.../legacy.zip?sig=x"