diff --git a/docs/changelog.mdx b/docs/changelog.mdx
new file mode 100644
index 000000000..74c86fd19
--- /dev/null
+++ b/docs/changelog.mdx
@@ -0,0 +1,127 @@
+---
+title: "Changelog"
+description: "New features, improvements, and fixes in Skyvern"
+---
+
+
+
+## New features
+
+- **Adaptive Caching (Script Generation)** — Skyvern can now learn from repeated workflow runs and generate cached scripts that speed up future executions. When a block runs successfully, Skyvern records a reusable script and replays it on subsequent runs, falling back to the AI agent only if the script fails. ([#4908](https://github.com/Skyvern-AI/skyvern/pull/4908), [#4916](https://github.com/Skyvern-AI/skyvern/pull/4916), [#4917](https://github.com/Skyvern-AI/skyvern/pull/4917), [#4920](https://github.com/Skyvern-AI/skyvern/pull/4920), [#4922](https://github.com/Skyvern-AI/skyvern/pull/4922), [#4931](https://github.com/Skyvern-AI/skyvern/pull/4931))
+
+- **Workflow Trigger Block** — A new block type that lets one workflow trigger another from within the workflow editor. Chain workflows together as building blocks for complex automations. ([#4885](https://github.com/Skyvern-AI/skyvern/pull/4885))
+
+- **Browser-based CLI Signup** — New users can sign up for Skyvern Cloud directly from the CLI. Running `skyvern signup` opens a browser flow that creates your account and stores your API key locally. ([#4925](https://github.com/Skyvern-AI/skyvern/pull/4925))
+
+- **Interactive ngrok Tunnel** — `skyvern browser serve` can now create an ngrok tunnel automatically, making it easy to expose your local browser to Skyvern Cloud without manual network configuration. ([#4924](https://github.com/Skyvern-AI/skyvern/pull/4924))
+
+- **South Korea Proxy Location** — Added `RESIDENTIAL_KR` as a proxy geolocation option for automations targeting South Korean websites. ([#4918](https://github.com/Skyvern-AI/skyvern/pull/4918))
+
+- **Downloaded Files Tab** — Browser session detail pages now include a Downloaded Files tab for viewing and accessing files captured during a session. ([#4911](https://github.com/Skyvern-AI/skyvern/pull/4911))
+
+- **CDP Proxy Authentication** — Remote browser connections now support authenticated proxies via the CDP `Fetch.authRequired` protocol. ([#4936](https://github.com/Skyvern-AI/skyvern/pull/4936))
+
+- **Remote Browser Download Interception** — File downloads triggered by XHR requests and other non-navigation events are now captured when using remote CDP browser connections. ([#4906](https://github.com/Skyvern-AI/skyvern/pull/4906), [#4921](https://github.com/Skyvern-AI/skyvern/pull/4921), [#4934](https://github.com/Skyvern-AI/skyvern/pull/4934))
+
+## Improvements
+
+- **Renamed "Login-Free" to "Saved Profile"** — Clearer terminology throughout the UI. Browser session checkbox wording has also been improved. ([#4914](https://github.com/Skyvern-AI/skyvern/pull/4914))
+
+- **TOTP Verification Improvements** — Better timer handling, expired code retry, 2FA banner suppression, and more reliable goal-text extraction during TOTP flows. ([#4860](https://github.com/Skyvern-AI/skyvern/pull/4860))
+
+- **TOTP Webhook includes `workflow_permanent_id`** — Easier to identify which workflow is requesting a 2FA code. ([#4871](https://github.com/Skyvern-AI/skyvern/pull/4871))
+
+- **Consolidated Gemini 3 Pro Model Key** — `VERTEX_GEMINI_3_PRO` now auto-resolves to the latest version, so you no longer need to update config when Google releases point versions. ([#4926](https://github.com/Skyvern-AI/skyvern/pull/4926))
+
+- **Browser Rotation for Remote Connections** — Remote browser environments now support context rotation, improving reliability for long-running automations. ([#4929](https://github.com/Skyvern-AI/skyvern/pull/4929))
+
+## Bug fixes
+
+- Fixed a race condition where final task status could be overwritten by a late-arriving non-final status. ([#4928](https://github.com/Skyvern-AI/skyvern/pull/4928))
+- Conditional blocks no longer crash when evaluating empty or null parameters. ([#4907](https://github.com/Skyvern-AI/skyvern/pull/4907))
+- Browser sessions using `FORCE_BROWSER_SESSION` no longer time out prematurely. ([#4903](https://github.com/Skyvern-AI/skyvern/pull/4903))
+- SVG-based captcha text is now correctly extracted during DOM scraping. ([#4880](https://github.com/Skyvern-AI/skyvern/pull/4880))
+- MCP remote tool handlers now route to the correct API environment. ([#4869](https://github.com/Skyvern-AI/skyvern/pull/4869))
+- MCP remote auth token comparison no longer fails on encrypted tokens. ([#4863](https://github.com/Skyvern-AI/skyvern/pull/4863))
+- `skyvern quickstart` now handles local PostgreSQL without a pre-existing `skyvern` role. ([#4878](https://github.com/Skyvern-AI/skyvern/pull/4878))
+- WebSocket URLs through ngrok tunnels now rewrite correctly for live browser streaming. ([#4927](https://github.com/Skyvern-AI/skyvern/pull/4927))
+
+
+
+
+
+## New features
+
+- **`current_date` Reserved Parameter** — Workflows now have a built-in `current_date` parameter that resolves to today's date automatically. ([#4854](https://github.com/Skyvern-AI/skyvern/pull/4854))
+
+- **Reserved Parameters in Block Editor** — The workflow block parameter picker now shows reserved system parameters, making them discoverable without memorizing names. ([#4857](https://github.com/Skyvern-AI/skyvern/pull/4857))
+
+- **Natural Language Loop `data_schema`** — Loop blocks driven by natural language extraction now support a `data_schema` field for consistent output structure. ([#4851](https://github.com/Skyvern-AI/skyvern/pull/4851))
+
+- **Gemini 3.1 Pro and Inception Mercury-2** — Two new LLM engine options for your automations. ([#4847](https://github.com/Skyvern-AI/skyvern/pull/4847))
+
+- **MCP Server on API Service** — The MCP remote server is now mounted at `/mcp` on the existing API, eliminating the need for a separate process. ([#4843](https://github.com/Skyvern-AI/skyvern/pull/4843))
+
+## Improvements
+
+- Workflow save validation (HTTP 422) now returns clear, field-level error messages. ([#4852](https://github.com/Skyvern-AI/skyvern/pull/4852))
+- Browser launch errors now show actionable messages instead of raw exceptions. ([#4844](https://github.com/Skyvern-AI/skyvern/pull/4844))
+- Cloud LLM fallback overrides are now properly applied when selecting models. ([#4839](https://github.com/Skyvern-AI/skyvern/pull/4839))
+
+## Bug fixes
+
+- Conditional blocks no longer crash when all branches use Jinja templates. ([#4849](https://github.com/Skyvern-AI/skyvern/pull/4849))
+- Conditional blocks no longer misinterpret resolved Jinja template variables. ([#4841](https://github.com/Skyvern-AI/skyvern/pull/4841))
+
+
+
+
+
+## New features
+
+- **Browser Profile Testing** — Test browser profiles directly from the UI to verify that saved login sessions are still valid. Workflows can also run with a saved browser profile, enabling login-free automations that reuse authenticated sessions. ([#4818](https://github.com/Skyvern-AI/skyvern/pull/4818))
+
+## Bug fixes
+
+- When both a TOTP credential and a webhook are configured for 2FA, the credential is now correctly prioritized. ([#4811](https://github.com/Skyvern-AI/skyvern/pull/4811))
+
+
+
+
+
+## New features
+
+- **Skyvern Skills Package** — The new `skyvern skill` CLI command provides pre-built workflow templates and reference documentation for common automation patterns. ([#4817](https://github.com/Skyvern-AI/skyvern/pull/4817))
+
+- **Clear Cached Scripts API** — A new endpoint lets you clear cached automation scripts for a workflow when a target website changes and you want to force Skyvern to re-learn. ([#4809](https://github.com/Skyvern-AI/skyvern/pull/4809))
+
+
+
+
+
+## New features
+
+- **Automatic 2FA Detection Without TOTP Credentials** — Skyvern now detects when a website asks for a 2FA code even without pre-configured TOTP credentials. The system pauses and waits for you to provide the code via the UI or webhook. ([#4786](https://github.com/Skyvern-AI/skyvern/pull/4786))
+
+- **Full CLI Parity with MCP** — The CLI now supports browser session management, credential management, block operations, and enhanced workflow commands. Everything available through MCP is now accessible from the command line. ([#4789](https://github.com/Skyvern-AI/skyvern/pull/4789), [#4792](https://github.com/Skyvern-AI/skyvern/pull/4792), [#4793](https://github.com/Skyvern-AI/skyvern/pull/4793))
+
+- **Claude Opus 4.6 CUA Support** — Anthropic's Claude Opus 4.6 is now available as a Computer Use Agent model for driving browser interactions. ([#4780](https://github.com/Skyvern-AI/skyvern/pull/4780))
+
+## Improvements
+
+- The workflow run timeline now properly displays loop iterations and conditional branches, making complex runs easier to debug. ([#4782](https://github.com/Skyvern-AI/skyvern/pull/4782))
+
+## Bug fixes
+
+- Fixed conditional blocks evaluating the wrong value after Jinja template rendering. ([#4801](https://github.com/Skyvern-AI/skyvern/pull/4801))
+- Fixed MFA resolution priority when both TOTP credentials and webhooks are configured. ([#4800](https://github.com/Skyvern-AI/skyvern/pull/4800))
+
+
+
+
+
+## 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))
+
+
diff --git a/docs/cloud/account-settings/api-keys.mdx b/docs/cloud/account-settings/api-keys.mdx
index 5f8892389..a7f198aa6 100644
--- a/docs/cloud/account-settings/api-keys.mdx
+++ b/docs/cloud/account-settings/api-keys.mdx
@@ -24,7 +24,7 @@ Every Skyvern API request requires the `x-api-key` header:
curl -X POST "https://api.skyvern.com/v1/runs" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
- -d '{ "url": "https://example.com", "goal": "Extract the pricing table" }'
+ -d '{ "url": "https://example.com", "prompt": "Extract the pricing table" }'
```
With the Python SDK:
diff --git a/docs/cloud/getting-started/monitor-a-run.mdx b/docs/cloud/getting-started/monitor-a-run.mdx
index d341412bd..29232725c 100644
--- a/docs/cloud/getting-started/monitor-a-run.mdx
+++ b/docs/cloud/getting-started/monitor-a-run.mdx
@@ -31,7 +31,6 @@ The live browser stream is active while the task is still in progress:
| `created` | Waiting to start |
| `queued` | Waiting for a browser |
| `running` | **Active**: the browser is navigating |
-| `paused` | Waiting for human interaction |
| `completed` | Stream closed. View the recording instead. |
| `failed` | Stream closed. View the recording instead. |
| `terminated` | Stream closed. View the recording instead. |
diff --git a/docs/cloud/getting-started/overview.mdx b/docs/cloud/getting-started/overview.mdx
index a28fa5eda..ca6edbd5e 100644
--- a/docs/cloud/getting-started/overview.mdx
+++ b/docs/cloud/getting-started/overview.mdx
@@ -38,7 +38,7 @@ Ready-made automation templates. Each agent is preconfigured with a prompt, targ
| Page | Purpose |
|------|---------|
| **Billing** | Usage, remaining credits, and plan management. |
-| **Credentials** | Store website logins securely. Skyvern uses these to authenticate automatically when it encounters a login page. |
+| **Credentials** | Store website logins, credit card details, and secret values securely. Skyvern uses these to authenticate automatically, fill payment forms, and inject secrets into workflows. |
| **Settings** | API key, account preferences, and organization management. |
## How it works
diff --git a/docs/cloud/managing-credentials/credentials-overview.mdx b/docs/cloud/managing-credentials/credentials-overview.mdx
index bcaca34ff..c8b43d1c3 100644
--- a/docs/cloud/managing-credentials/credentials-overview.mdx
+++ b/docs/cloud/managing-credentials/credentials-overview.mdx
@@ -4,74 +4,99 @@ subtitle: Securely store login details, payment info, and secrets for your autom
slug: cloud/managing-credentials/credentials-overview
---
-The **Credentials** page stores sensitive values — passwords, payment cards, and secrets — so your workflows can use them without you pasting passwords into prompts.
-
-
-Credentials **never reach the LLM**. The AI agent decides *where* to type, but the actual values are injected directly into the browser by the automation layer. Your credentials aren't exposed in prompts, logs, or model provider APIs.
-
+The **Credentials** page stores sensitive values (passwords, payment cards, and secrets) so your workflows can use them without embedding secrets in prompts or parameters. Skyvern stores credentials by default with no external service required.
+## How Skyvern keeps credentials secure
+
+Sensitive credential data never reaches the LLM, logs, or API responses.
+
+
+
+ When you save a credential, the sensitive data (passwords, card numbers, CVVs, and TOTP secrets) is sent to a secure vault that provides encryption at rest. Skyvern supports multiple vault backends: Bitwarden, 1Password, Azure Key Vault, and custom webhook providers. Skyvern's own database stores only non-sensitive metadata: credential name, username, card last four digits, card brand, TOTP method, and similar identifiers. Passwords, full card numbers, CVVs, and TOTP secrets are stored exclusively in the vault.
+
+
+ When a workflow runs, the LLM receives only placeholder IDs like `placeholder_Xk9m_password`. The AI decides *where* to type on the page, but never sees the real values. No third party, including the LLM provider, ever accesses your actual credentials.
+
+
+ At the browser level, the automation layer resolves placeholders to real values and types them directly into the page. After execution, credential values that appear in HTTP Request block responses, block context snapshots, and conditional evaluation outputs are automatically masked before storage.
+
+
+
+---
+
+## Quick start
+
+
+
+ Click **Credentials** in the left sidebar under **General**.
+
+
+
+ Choose the credential type: **Password**, **Credit Card**, or **Secret**.
+
+
+
+ Enter the required fields and click **Save**. The credential is immediately available for use in workflows.
+
+
+
+---
+
## What you can store
-**[Password credentials](/cloud/managing-credentials/password-credentials)** — username, password, and optional 2FA configuration. Used with Login blocks to automate full sign-in flows, including two-factor authentication.
+
+
+ Username, password, and optional 2FA configuration for automated logins
+
+
+ Payment card details for purchase and checkout workflows
+
+
+ A single sensitive string such as an API key, bearer token, or any value you don't want hardcoded
+
+
-**[Credit card credentials](/cloud/managing-credentials/credit-card-credentials)** — payment card details (number, expiration, CVV, cardholder name). Used in workflows that complete purchases or fill billing forms.
+Password and Credit Card credentials have their own pages. Secrets are simpler and documented here.
-**Secret credentials** — a single sensitive string: API key, bearer token, encryption key, or anything you don't want hardcoded. Create one from **+ Add → Secret** and reference it in any parameter field:
+### Secret credentials
+
+Secrets store a single sensitive value (an API key, bearer token, or similar). Create one from **+ Add → Secret**, give it a name and value, then reference it in HTTP Request, Code, or Workflow Trigger blocks using the credential parameter's key:
```
-{{ credential_name.secret_value }}
+{{ parameter_key.secret_value }}
```
-## External credential providers
+Replace `parameter_key` with the **key** assigned to the credential parameter in the workflow editor (e.g., `credentials`, `credentials_1`).
-If your organization already manages secrets in a dedicated vault, reference them directly from **Bitwarden**, **1Password**, or **Azure Key Vault** by adding credential parameters in the [workflow editor](/cloud/building-workflows/add-parameters).
+---
-### Bitwarden
+## Using credentials in workflows
-Works with hosted Bitwarden and the self-hosted [Vaultwarden](https://github.com/dani-garcia/vaultwarden) fork. Supports passwords, credit cards, and identity data (SSN, address, phone numbers).
+The most common pattern is a **Login block**. A Login block is a workflow step that signs into a website using stored credentials. Select a credential from the dropdown, and Skyvern fills in the username, password, and 2FA code (if configured) automatically. See [Block Reference](/cloud/building-workflows/configure-blocks) for details.
-Point a credential parameter at a specific vault item using the **Collection ID** and **Item ID** from the Bitwarden web UI. Alternatively, set a **URL Parameter Key** so Bitwarden matches credentials by the target URL — useful when the same workflow runs against different sites.
+For workflows that need different credentials at runtime, add a **Credential parameter** (type: `credential_id`). When someone runs the workflow, they pick which credential to use from a dropdown. See [Workflow Parameters](/cloud/building-workflows/add-parameters) for setup.
-For identity data, specify an **Identity Key** and a comma-separated list of **Identity Fields** (e.g., `ssn, address, phone`).
-
-### 1Password
-
-Connects via a service account token. Supports passwords and credit cards.
-
-**One-time setup:** Go to **Settings** → find the **1Password** card → paste your [service account token](https://developer.1password.com/docs/service-accounts/get-started/) → click **Update**. The status indicator turns **Active** once validated.
-
-In the workflow editor, select **1Password** as the credential source and provide the **Vault ID** and **Item ID** from your 1Password web URLs.
-
-
-Credit cards from 1Password need a text field named **"Expire Date"** on the item in `MM/YYYY` format. This is a workaround for how 1Password structures card data.
-
-
-### Azure Key Vault
-
-Pulls credentials stored as Azure secrets. Supports passwords with optional TOTP.
-
-**One-time setup:** Go to **Settings** → find the **Azure** card → enter your **Tenant ID**, **Client ID**, and **Client Secret** → click **Update**.
-
-In the workflow editor, select **Azure Key Vault** as the credential source and point it at your vault by name. Provide the **secret names** that store the username and password (and optionally a TOTP secret for 2FA) — not the values themselves.
-
-### Which source should you use?
-
-| Source | Best for |
-|--------|----------|
-| **Skyvern built-in** | Fastest setup — create credentials directly in the UI, no external dependencies |
-| **Bitwarden** | Teams already using Bitwarden who don't want to manage credentials in two places |
-| **1Password** | Teams already using 1Password with service account access |
-| **Azure Key Vault** | Enterprise environments with centrally managed Azure secrets |
-
-You can mix sources within the same workflow — one Login block using Skyvern-stored credentials and another using Azure Key Vault.
+---
## Deleting credentials
-Click the **trash icon** on any credential. Deletion is permanent — the Skyvern team can't restore deleted credentials. If a workflow references a deleted credential, it will fail at the login step until you assign a replacement.
+Click the **trash icon** on any credential row. Deletion is permanent and cannot be undone. If a workflow references a deleted credential, the run will fail during initialization until you assign a replacement.
-
+
- Store payment details for purchase workflows
+ Store payment details for checkout workflows
Configure and manage two-factor authentication
+
+ Connect Bitwarden, 1Password, Azure Key Vault, or a custom API
+
diff --git a/docs/cloud/managing-credentials/credit-card-credentials.mdx b/docs/cloud/managing-credentials/credit-card-credentials.mdx
index 3ed2d1e00..ba494a38a 100644
--- a/docs/cloud/managing-credentials/credit-card-credentials.mdx
+++ b/docs/cloud/managing-credentials/credit-card-credentials.mdx
@@ -4,38 +4,54 @@ subtitle: Store payment details for purchase and checkout workflows
slug: cloud/managing-credentials/credit-card-credentials
---
-Credit card credentials store payment details so the AI can fill checkout forms without you embedding card numbers in prompts or parameters.
+Credit card credentials store payment details so the AI can fill checkout forms without you embedding card numbers in prompts or parameters. Like all credentials, card numbers never reach the LLM. They are injected directly at the browser level.
## Creating a credit card credential
-Click **+ Add → Credit Card** from the Credentials page. Provide the full card details:
+
+
+ Click **+ Add → Credit Card** from the Credentials page.
+
+
+ Provide all required fields:
-| Field | Description |
-|-------|------------|
-| **Name** | A label like "Corporate Visa" to identify it later |
-| **Cardholder Name** | Name printed on the card |
-| **Number** | Full card number (spaces added automatically as you type) |
-| **Brand** | Card network: Visa, Mastercard, American Express, Discover, JCB, Diners Club, Maestro, UnionPay, RuPay, or Other |
-| **Expiration** | Month and year in `MM/YY` format (slash inserted automatically) |
-| **CVV** | 3 or 4 digit security code |
+ | Field | Description |
+ |-------|------------|
+ | **Name** | A label like "Corporate Visa" to identify it later |
+ | **Cardholder Name** | Name printed on the card |
+ | **Number** | Full card number (spaces added automatically as you type) |
+ | **Brand** | Card network: Visa, Mastercard, American Express, Discover, JCB, Diners Club, Maestro, UnionPay, RuPay, or Other |
+ | **Expiration** | Month and year in `MM/YY` format (slash inserted automatically) |
+ | **CVV** | 3 or 4 digit security code |
+
+
+ Click **Save**. After saving, the card number is masked and only the last four digits are ever shown again.
+
+
-After saving, the card number is masked — only the last four digits are ever shown again.
+
+
+
## Using credit cards in workflows
-Credit cards work with **Browser Task** and **Browser Action** blocks that interact with checkout pages. The AI identifies payment fields on the page and fills them with the stored details.
+Credit cards work with [**Browser Task** and **Browser Action**](/cloud/building-workflows/configure-blocks) blocks that interact with checkout pages. The AI automatically recognizes standard checkout forms and fills card number, name, expiration, and CVV fields with the stored details. No field mapping is required.
-To reference a credit card, add a **Credential parameter** (type: `credential_id`) and select the card when running the workflow. This lets the same checkout workflow work with different payment methods.
+For workflows that need different cards at runtime, add a **Credential parameter** (type: `credential_id`) in the [workflow editor](/cloud/building-workflows/add-parameters). When someone runs the workflow, they select which card to use from a dropdown. This lets the same checkout workflow work with different payment methods.
-Credit cards from **1Password** need a text field named **"Expire Date"** in `MM/YYYY` format on the 1Password item. See [Credentials Overview](/cloud/managing-credentials/credentials-overview#1password) for details.
+If you use 1Password as a credential provider, credit cards require a custom text field named **"Expire Date"**, **"Expiry Date"**, or **"Expiration Date"** in `MM/YYYY` or `MM/YY` format. 1Password does not expose the native expiration field through its API, so Skyvern reads this custom text field instead. See [External Providers](/cloud/managing-credentials/external-providers#1password) for full setup details.
## Editing and deleting
-Credit card credentials can't be edited after creation. If card details change, delete the old credential and create a new one. Click the **trash icon** to delete — the action is permanent.
+
+To edit a credential, click the **pencil icon** on its row. For security, saved card details are never retrieved, so you must re-enter all fields when updating.
+
-
+Click the **trash icon** on any credential row to delete it. Deletion is permanent and cannot be undone.
+
+
Store login details with optional 2FA
+
+ Connect Bitwarden, 1Password, Azure Key Vault, or a custom API
+
- All credential types, external providers, and security model
+ Security model, quick start, and all credential types
diff --git a/docs/cloud/managing-credentials/external-providers.mdx b/docs/cloud/managing-credentials/external-providers.mdx
new file mode 100644
index 000000000..180ee1822
--- /dev/null
+++ b/docs/cloud/managing-credentials/external-providers.mdx
@@ -0,0 +1,383 @@
+---
+title: External Credential Providers
+subtitle: Connect Bitwarden, 1Password, Azure Key Vault, or your own vault API
+slug: cloud/managing-credentials/external-providers
+---
+
+Instead of copying secrets into Skyvern, you can point Skyvern at your existing vault and it pulls credentials at runtime. If your organization already manages secrets in a dedicated vault, connect it as a credential source and reference items directly from workflow parameters.
+
+
+External providers are configured per-organization. Once connected, any workflow in the organization can reference credentials from that provider.
+
+
+## Choosing a provider
+
+| Source | Credential types | Setup | Best for |
+|--------|-----------------|-------|----------|
+| **Skyvern** (default) | Password, Credit Card, Secret | None (built in) | Most users, fastest setup |
+| **Bitwarden** | Password, Credit Card, Identity | Credential parameter config | Teams already using Bitwarden (enterprise) |
+| **1Password** | Password, Credit Card | Settings page setup | Teams with 1Password service accounts |
+| **Azure Key Vault** | Password (with optional TOTP) | Settings page setup | Enterprise Azure environments |
+| **Webhook (Custom API)** | Password, Credit Card | Settings page setup | Organizations with custom vaults |
+
+You can mix sources within the same workflow. For example, one Login block can use Skyvern-stored credentials while another uses Azure Key Vault.
+
+---
+
+## Bitwarden
+
+
+Bitwarden integration is available on the **enterprise plan**. Contact [sales@skyvern.com](mailto:sales@skyvern.com) for access.
+
+
+Works with hosted Bitwarden and the self-hosted [Vaultwarden](https://github.com/dani-garcia/vaultwarden) fork. Supports passwords, credit cards, and identity data (SSN, address, phone numbers).
+
+
+Make sure your Bitwarden account is on `bitwarden.com`, not `bitwarden.eu`. The EU instance uses a different API that Skyvern does not currently support.
+
+
+### Cloud setup
+
+
+
+ Log into Bitwarden, navigate to **Admin Console**, and ensure you have an organization created.
+
+
+ In your organization, click **New → Create a collection**. Name it something identifiable (e.g., "Skyvern Credentials"). Skip this step if you already have a collection ready.
+
+
+ Go to the **Access** tab on your collection. This step requires coordination with the Skyvern enterprise team, who will configure access on their end. Contact [sales@skyvern.com](mailto:sales@skyvern.com) to get started.
+
+
+ Click into the collection and find the collection UUID in the URL bar.
+
+
+ In the Skyvern workflow editor, click **Parameters → Add Parameter → Credential Parameter** and select the **Bitwarden** tab. Enter your **Collection ID** and optionally an **Item ID** to target a specific vault item.
+
+
+
+### Configuration options
+
+| Field | Description |
+|-------|------------|
+| **Collection ID** | The UUID of your Bitwarden collection (found in the URL when viewing the collection) |
+| **Item ID** | Target a specific vault item. Leave blank to use URL matching instead. |
+| **URL Parameter Key** | Match credentials by the target URL. Useful when the same workflow runs against different sites. |
+
+### Identity data
+
+For identity fields (SSN, address, phone numbers), specify an **Identity Key** and a comma-separated list of **Identity Fields** (e.g., `ssn, address, phone`) in the Credential Parameter configuration panel.
+
+
+Skyvern integrates with self-hosted Bitwarden-compatible services like Vaultwarden using the Bitwarden CLI server as a bridge:
+
+```text
+Skyvern → bw serve (CLI Server) → Vaultwarden
+```
+
+**Environment variables:**
+
+```bash
+# Skyvern Bitwarden Configuration
+SKYVERN_AUTH_BITWARDEN_ORGANIZATION_ID=your-org-id-here
+SKYVERN_AUTH_BITWARDEN_MASTER_PASSWORD=your-master-password-here
+SKYVERN_AUTH_BITWARDEN_CLIENT_ID=user.your-client-id-here
+SKYVERN_AUTH_BITWARDEN_CLIENT_SECRET=your-client-secret-here
+
+# Vaultwarden Configuration
+BW_HOST=https://your-vaultwarden-server.com
+BW_CLIENTID=${SKYVERN_AUTH_BITWARDEN_CLIENT_ID}
+BW_CLIENTSECRET=${SKYVERN_AUTH_BITWARDEN_CLIENT_SECRET}
+BW_PASSWORD=${SKYVERN_AUTH_BITWARDEN_MASTER_PASSWORD}
+
+# CLI Server Configuration
+BITWARDEN_SERVER=http://localhost
+BITWARDEN_SERVER_PORT=8002
+```
+
+Start the CLI server with Docker Compose:
+
+```bash
+docker-compose up -d bitwarden-cli
+```
+
+Verify it's running:
+
+```bash
+curl http://localhost:8002/status
+```
+
+
+---
+
+## 1Password
+
+Connects via a [service account token](https://developer.1password.com/docs/service-accounts/get-started/). A service account is an API-only identity that accesses vault items without a human login. Supports passwords and credit cards.
+
+### One-time setup
+
+
+
+ In your 1Password admin console, go to **Developer > Service Accounts** and create a new service account. Grant it access to the vault that contains the credentials Skyvern needs.
+
+
+ In Skyvern, go to **Settings** and find the **1Password** card.
+
+
+ Paste the service account token from the previous step.
+
+
+ Click **Update**. The status indicator turns **Active** once the token is validated.
+
+
+
+
+If the status does not turn Active, verify that your service account token has access to the target vault and has not expired.
+
+
+### Using in a workflow
+
+In the workflow editor, add a **Credential Parameter** and select **1Password** as the source. Provide the **Vault ID** and **Item ID**. You can find both IDs in the URL when viewing an item in the 1Password web app.
+
+
+Credit cards from 1Password need a custom text field named **"Expire Date"**, **"Expiry Date"**, or **"Expiration Date"** in `MM/YYYY` or `MM/YY` format. 1Password does not expose the native expiration field through its API, so Skyvern reads this custom text field instead.
+
+
+---
+
+## Azure Key Vault
+
+Pulls credentials stored as Azure secrets. Supports passwords with optional TOTP.
+
+### One-time setup
+
+
+
+ Go to **Settings** and find the **Azure** card.
+
+
+ Provide your **Tenant ID**, **Client ID**, and **Client Secret**.
+
+
+ Click **Update**. Skyvern will use these credentials to access your vault.
+
+
+
+### Using in a workflow
+
+In the workflow editor, add a **Credential Parameter** and select **Azure Key Vault** as the source. Provide the vault name and the **secret names** that store the username, password, and optionally a TOTP secret. Enter the secret names, not the values themselves.
+
+For example, if your vault stores secrets named `salesforce-username`, `salesforce-password`, and `salesforce-totp`, enter those three names in the corresponding fields.
+
+---
+
+## Webhook (Custom API)
+
+Connect your own HTTP API as a credential backend. Skyvern calls your API to create, retrieve, and delete credentials, so sensitive data stays in your infrastructure.
+
+### API contract
+
+Your service must implement three endpoints. All requests include an `Authorization: Bearer {API_TOKEN}` header.
+
+**Create credential**
+```http
+POST {API_BASE_URL}
+Authorization: Bearer {API_TOKEN}
+Content-Type: application/json
+```
+
+The request body depends on the credential type. Your API must handle all three:
+
+
+```json
+{
+ "name": "Salesforce Login",
+ "type": "password",
+ "username": "user@example.com",
+ "password": "secure_password",
+ "totp": "JBSWY3DPEHPK3PXP",
+ "totp_type": "authenticator"
+}
+```
+The `totp` and `totp_type` fields are optional. `totp_type` can be `"authenticator"`, `"email"`, `"text_message"`, or `"none"`.
+
+
+
+```json
+{
+ "name": "Corporate Visa",
+ "type": "credit_card",
+ "card_holder_name": "Jane Doe",
+ "card_number": "4111111111111111",
+ "card_exp_month": "12",
+ "card_exp_year": "2025",
+ "card_cvv": "123",
+ "card_brand": "visa"
+}
+```
+
+
+
+```json
+{
+ "name": "Stripe API Key",
+ "type": "secret",
+ "secret_value": "sk_live_abc123",
+ "secret_label": "api-key"
+}
+```
+The `secret_label` field is optional.
+
+
+Response (all types):
+```json
+{
+ "id": "cred_123456"
+}
+```
+
+**Get credential**
+```http
+GET {API_BASE_URL}/{credential_id}
+Authorization: Bearer {API_TOKEN}
+```
+
+Return the same fields that were sent during creation (minus `name`). Include `type` so Skyvern knows how to parse the response.
+
+**Delete credential**
+```http
+DELETE {API_BASE_URL}/{credential_id}
+Authorization: Bearer {API_TOKEN}
+```
+
+Response: HTTP 200
+
+### Setup
+
+
+
+ Go to **Settings** and find the **Custom Credential Service** card.
+
+
+ Provide the **API Base URL** and **API Token** for your credential service.
+
+
+ Click **Update Configuration**. The status indicator turns **Active** once the configuration is saved.
+
+
+
+
+```python
+from fastapi import FastAPI, HTTPException, Depends, Header
+from pydantic import BaseModel
+from typing import Optional
+import uuid
+
+app = FastAPI()
+credentials_store = {}
+
+class CreateCredentialRequest(BaseModel):
+ name: str
+ type: str # "password", "credit_card", or "secret"
+ # Password fields
+ username: Optional[str] = None
+ password: Optional[str] = None
+ totp: Optional[str] = None
+ totp_type: Optional[str] = None
+ # Credit card fields
+ card_holder_name: Optional[str] = None
+ card_number: Optional[str] = None
+ card_exp_month: Optional[str] = None
+ card_exp_year: Optional[str] = None
+ card_cvv: Optional[str] = None
+ card_brand: Optional[str] = None
+ # Secret fields
+ secret_value: Optional[str] = None
+ secret_label: Optional[str] = None
+
+class CredentialResponse(BaseModel):
+ id: str
+
+def verify_token(authorization: str = Header(...)):
+ if not authorization.startswith("Bearer "):
+ raise HTTPException(401, "Invalid authorization header")
+ token = authorization.split("Bearer ")[1]
+ if token != "your_expected_api_token":
+ raise HTTPException(401, "Invalid API token")
+
+@app.post("/api/v1/credentials", response_model=CredentialResponse)
+async def create_credential(
+ request: CreateCredentialRequest,
+ _: None = Depends(verify_token)
+):
+ credential_id = f"cred_{uuid.uuid4().hex[:12]}"
+ credentials_store[credential_id] = request.model_dump()
+ return CredentialResponse(id=credential_id)
+
+@app.get("/api/v1/credentials/{credential_id}")
+async def get_credential(
+ credential_id: str,
+ _: None = Depends(verify_token)
+):
+ if credential_id not in credentials_store:
+ raise HTTPException(404, "Credential not found")
+ return credentials_store[credential_id]
+
+@app.delete("/api/v1/credentials/{credential_id}")
+async def delete_credential(
+ credential_id: str,
+ _: None = Depends(verify_token)
+):
+ if credential_id not in credentials_store:
+ raise HTTPException(404, "Credential not found")
+ del credentials_store[credential_id]
+ return {"status": "deleted"}
+```
+
+
+
+For self-hosted Skyvern deployments, set these environment variables instead of using the Settings UI:
+
+```bash
+CREDENTIAL_VAULT_TYPE=custom
+CUSTOM_CREDENTIAL_API_BASE_URL=https://credentials.company.com/api/v1/credentials
+CUSTOM_CREDENTIAL_API_TOKEN=your_api_token_here
+```
+
+Restart Skyvern after setting these variables.
+
+
+### Troubleshooting
+
+| Problem | What to check |
+|---------|--------------|
+| Status stays Inactive | Verify the API base URL is a valid URL and the API token is not empty. The configuration is validated on save but does not make a live request to your server. |
+| Credentials not created | Review your API logs for auth errors. Ensure the response includes an `id` field. Skyvern expects HTTP 200 for all operations. |
+| Credentials not retrieved | Ensure the GET response includes all required fields for the credential type (`username` and `password` for passwords, all card fields for credit cards, `secret_value` for secrets). |
+| Env config not working | Restart Skyvern after setting variables. Verify `CREDENTIAL_VAULT_TYPE=custom` is set and both URL and token are provided. The default vault type is `bitwarden`, so this variable must be explicitly set. |
+
+---
+
+
+
+ Built-in credential storage, security model, and quick start
+
+
+ Store login details with optional 2FA
+
+
+ Configure credential parameters in the workflow editor
+
+
diff --git a/docs/cloud/managing-credentials/password-credentials.mdx b/docs/cloud/managing-credentials/password-credentials.mdx
index 15031463c..40f07f975 100644
--- a/docs/cloud/managing-credentials/password-credentials.mdx
+++ b/docs/cloud/managing-credentials/password-credentials.mdx
@@ -1,19 +1,30 @@
---
title: Password Credentials
-subtitle: Store login details and use them in automated workflows
+subtitle: Store login details and use them in automated sign-in flows
slug: cloud/managing-credentials/password-credentials
---
-Password credentials store a username, password, and optional 2FA configuration. Reference them from Login blocks in your workflows, and Skyvern handles the entire sign-in flow — including entering 2FA codes.
+Password credentials store a username, password, and optional 2FA configuration. Reference them from [Login blocks](/cloud/building-workflows/configure-blocks) in your workflows, and Skyvern handles the entire sign-in flow, including entering 2FA codes.
## Creating a password credential
-Click **+ Add → Password** from the Credentials page. Three fields: **Name** (a label like "Salesforce Production"), **Username or Email**, and **Password**. The password field has an eye icon to toggle visibility.
+
+
+ Click **+ Add → Password** from the Credentials page.
+
+
+ Enter a **Name** (a label like "Salesforce Production"), **Username or Email**, and **Password**. The password field has an eye icon to toggle visibility.
+
+
+ Expand the **Two-Factor Authentication** accordion to set up automated 2FA handling. See [below](#adding-two-factor-authentication) for details.
+
+
+ Click **Save**. The credential is immediately available for use in workflows.
+
+
-Save the credential and it's ready to use in a workflow.
-
## Adding two-factor authentication
If the site requires 2FA, expand the **Two-Factor Authentication** accordion below the password fields. Three options, depending on how the site delivers codes:
@@ -22,7 +33,7 @@ If the site requires 2FA, expand the **Two-Factor Authentication** accordion bel
| Method | How it works |
|--------|-------------|
-| **Authenticator App** | Paste the TOTP secret key and Skyvern generates codes locally on demand — fully automated, no delay. Preferred when the site supports it. |
+| **Authenticator App** | Paste the TOTP secret key and Skyvern generates codes locally on demand. Fully automated with no delay. Preferred when the site supports it. |
| **Email** | Provide the email address that receives codes. Skyvern waits for you to push the code via the [2FA tab](/cloud/managing-credentials/totp-setup) or API. Identifier auto-fills from the Username field. |
| **Text Message** | Provide the phone number that receives codes. Same push-based flow as Email. |
@@ -35,26 +46,23 @@ The secret key is the base32-encoded string behind the QR code you'd scan in an
- **Bitwarden**: Edit the login → TOTP field → copy the key
- **1Password**: Edit the login → One-Time Password → copy the secret
+- **LastPass**: Edit the login → Advanced Settings → copy the TOTP secret
- **Site settings**: Many sites show a "Can't scan?" link during 2FA setup that reveals the text key
If you only have a QR code, decode it to extract the `secret=` parameter from the `otpauth://totp/...?secret=BASE32KEY` URI.
-## Using credentials in workflows
+## Using credentials in a workflow
-The most common pattern is a **Login block**. Select the stored credential from the dropdown, and Skyvern navigates to the login page, enters the username and password, handles 2FA if configured, and waits for the page to confirm authentication. See [Block Reference → Login](/cloud/building-workflows/configure-blocks) for details.
-
-For workflows that need different accounts at runtime, use a **Credential parameter** (type: `credential_id`). When someone runs the workflow, they pick which credential to use from a dropdown.
-
-You can also pull credentials from **Bitwarden**, **1Password**, or **Azure Key Vault**. See [External Providers](/cloud/managing-credentials/credentials-overview#external-credential-providers).
+In the Login block configuration, select a stored credential from the dropdown. Skyvern fills in the username and password automatically, and handles 2FA if configured.
## Managing credentials
Stored credentials show the name, credential ID, username (plain text), password (always masked), and 2FA method if configured.
-
-Credentials can't be edited after creation. To change a password, delete the old credential and create a new one.
-
+
+To edit a credential, click the **pencil icon** on its row. For security, saved passwords and secrets are never retrieved, so you must re-enter all sensitive fields when updating.
+
+
+ Go to the Credentials page and create a new password credential.
+
+
+ Below the password fields, click the **Two-Factor Authentication** accordion.
+
+
+ Choose **Authenticator App** from the three options.
+
+
+ Enter the secret key into the **Authenticator Key** field and click **Save**.
+
+
-The flow:
+
+The secret key is the base32-encoded string behind the QR code you'd normally scan in an authenticator app. You can find it in a few places:
-1. Login block enters username and password
-2. Site sends a 2FA code to the configured email or phone
+- **Bitwarden**: Edit the login → TOTP field → copy the key
+- **1Password**: Edit the login → One-Time Password → copy the secret
+- **LastPass**: Edit the login → Advanced Settings → copy the TOTP secret
+- **Site settings**: Many sites show a "Can't scan?" link during 2FA setup that reveals the text key
+
+If you only have a QR code, decode it to extract the `secret=` parameter from the `otpauth://totp/...?secret=BASE32KEY` URI.
+
+
+---
+
+## Email and Text Message codes
+
+When a site sends 2FA codes via email or SMS, someone (or something) needs to deliver the code to Skyvern before the login can complete.
+
+### How it works
+
+1. The Login block enters the username and password
+2. The site sends a 2FA code to the configured email or phone number
3. You push the code to Skyvern via the **2FA tab** or the API
4. Skyvern enters the code and completes the login
-### Pushing a code manually
+### Setting it up
+
+
+
+ Go to the Credentials page and create a new password credential.
+
+
+ Below the password fields, click the **Two-Factor Authentication** accordion.
+
+
+ Choose the method that matches how the site delivers codes.
+
+
+ Provide the **email address** or **phone number** that receives the codes. For Email, this auto-fills from the Username field.
+
+
+
+---
+
+## Pushing codes to Skyvern
+
+Once a workflow is running and waiting for a 2FA code, you need to deliver it. There are two ways.
+
+### Via the UI
Open the **2FA** tab on the Credentials page. The **Push a 2FA Code** form has two fields:
| Field | What to enter |
|-------|--------------|
| **Identifier** | The email address or phone number that received the code |
-| **Verification content** | The full email/SMS body, or just the code itself — Skyvern extracts the digits automatically |
+| **Verification content** | The full email/SMS body, or just the code itself. Skyvern extracts the digits automatically. |
+
+
If multiple workflows are running simultaneously, click **Add optional metadata** to link the code to a specific run using the workflow run ID, workflow ID, or task ID.
-### Pushing codes via API
+### Via the API
-For production, automate code delivery. Set up a forwarding rule that sends 2FA emails/texts to a script, and the script calls:
+For production, automate code delivery. Set up a forwarding rule that sends 2FA emails or texts to a script, and the script pushes the code to Skyvern:
-```bash
+
+```bash cURL
curl -X POST "https://api.skyvern.com/v1/credentials/totp" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
@@ -53,15 +112,55 @@ curl -X POST "https://api.skyvern.com/v1/credentials/totp" \
}'
```
+```python Python
+from skyvern import Skyvern
+
+skyvern = Skyvern(api_key="YOUR_API_KEY")
+await skyvern.send_totp_code(
+ totp_identifier="user@example.com",
+ content="Your verification code is 847291",
+ source="email_forwarder",
+)
+```
+
+```typescript TypeScript
+import { SkyvernClient } from "@skyvern/client";
+
+const skyvern = new SkyvernClient({ apiKey: "YOUR_API_KEY" });
+await skyvern.sendTotpCode({
+ totp_identifier: "user@example.com",
+ content: "Your verification code is 847291",
+ source: "email_forwarder",
+});
+```
+
+
+**Response:**
+```json
+{
+ "totp_code_id": "tc_abc123",
+ "totp_identifier": "user@example.com",
+ "code": "847291",
+ "source": "email_forwarder",
+ "created_at": "2025-01-15T10:30:00Z"
+}
+```
+
The `source` field is a free-text label for your own tracking (e.g., `"email_forwarder"`, `"twilio_webhook"`).
-This turns email-based 2FA into something nearly as automated as authenticator app — the main difference is latency while the email arrives and gets forwarded.
+To link a code to a specific run, pass `workflow_run_id`, `workflow_id`, or `task_id`. This is the API equivalent of the **Add optional metadata** option in the UI.
+
+
+This turns email-based 2FA into something nearly as automated as an authenticator app. The main difference is latency while the email arrives and gets forwarded.
+
+
+---
## Viewing past codes
The table below the push form shows all 2FA codes your organization has received: identifier, extracted code, source type, associated workflow run, and timestamps. Filter by identifier, OTP type (numeric code vs. magic link), and number of results per page.
-Use this for auditing and debugging — confirming that a code was received and delivered to the right run.
+Use this for auditing and debugging: confirming that a code was received and delivered to the right run.
- All credential types, external providers, and security model
+ Security model, quick start, and all credential types
diff --git a/docs/debugging/faq.mdx b/docs/debugging/faq.mdx
index b3c0a5fe8..fc9e03be6 100644
--- a/docs/debugging/faq.mdx
+++ b/docs/debugging/faq.mdx
@@ -88,7 +88,7 @@ result = await client.run_workflow(
)
```
-Parameters are available in prompts using `{{ parameter_name }}` syntax. See [Workflow Parameters](/workflows/workflow-parameters) for details.
+Parameters are available in prompts using `{{ parameter_name }}` syntax. See [Workflow Parameters](/multi-step-automations/workflow-parameters) for details.
@@ -106,7 +106,7 @@ Skyvern doesn't have built-in scheduling yet. Use external schedulers like:
- **Zapier/Make** — Trigger workflows from automation platforms
- **Your backend** — Integrate scheduling into your application
-Set up a [webhook](/running-tasks/webhooks-faq) to get notified when scheduled runs complete.
+Set up a [webhook](/going-to-production/webhooks) to get notified when scheduled runs complete.
@@ -184,7 +184,7 @@ while True:
await asyncio.sleep(5)
```
-Or use [webhooks](/running-tasks/webhooks-faq) to get notified when runs complete without polling.
+Or use [webhooks](/going-to-production/webhooks) to get notified when runs complete without polling.
diff --git a/docs/docs.json b/docs/docs.json
index 147d8e487..cf9ba5473 100644
--- a/docs/docs.json
+++ b/docs/docs.json
@@ -121,7 +121,8 @@
"cloud/managing-credentials/credentials-overview",
"cloud/managing-credentials/password-credentials",
"cloud/managing-credentials/credit-card-credentials",
- "cloud/managing-credentials/totp-setup"
+ "cloud/managing-credentials/totp-setup",
+ "cloud/managing-credentials/external-providers"
]
},
{
@@ -187,18 +188,16 @@
"cookbooks/healthcare-portal-data"
]
},
+ {
+ "tab": "Changelog",
+ "pages": [
+ "changelog"
+ ]
+ },
{
"tab": "API Reference",
"openapi": "api-reference/openapi.json"
},
- {
- "tab": "Cookbooks",
- "pages": [
- "cookbooks/overview",
- "cookbooks/bulk-invoice-downloader",
- "cookbooks/job-application-filler"
- ]
- }
]
},
"navbar": {
diff --git a/docs/getting-started/core-concepts.mdx b/docs/getting-started/core-concepts.mdx
index ad32283f1..6640e6722 100644
--- a/docs/getting-started/core-concepts.mdx
+++ b/docs/getting-started/core-concepts.mdx
@@ -87,7 +87,7 @@ Workflows support Jinja templating:
**Use Workflows for:** repeatable automations, multi-step processes, team-shared templates, complex logic with loops or conditionals.
-See [Workflow Blocks](/workflows/workflow-blocks-details) for the full block reference.
+See [Workflow Blocks](/multi-step-automations/workflow-blocks-reference) for the full block reference.
---
@@ -304,7 +304,7 @@ await skyvern.run_workflow(
**What's saved:** Cookies, authentication tokens, local storage, session storage.
-See [Browser Sessions](/browser-sessions/introduction) for details.
+See [Browser Sessions](/optimization/browser-sessions) for details.
---
@@ -387,14 +387,14 @@ result = await skyvern.run_task(
Create multi-step automations
Full reference for all block types
diff --git a/docs/getting-started/quickstart.mdx b/docs/getting-started/quickstart.mdx
index 0086490ee..401e3d4ed 100644
--- a/docs/getting-started/quickstart.mdx
+++ b/docs/getting-started/quickstart.mdx
@@ -6,7 +6,7 @@ slug: getting-started/quickstart
Run your first browser automation in 5 minutes. By the end of this guide, you'll scrape the top post from Hacker News using Skyvern's AI agent.
-Prefer a visual interface? Try the [Cloud UI](/cloud/overview) instead — no code required.
+Prefer a visual interface? Try the [Cloud UI](/cloud/getting-started/overview) instead — no code required.
## Step 1: Get your API key
@@ -108,7 +108,7 @@ The response includes a `run_id` you'll use to check status and fetch results.
Since tasks run asynchronously, you have two options:
1. **Polling** — Periodically check the task status (shown below)
-2. **Webhooks** — Get notified when the task completes ([see webhooks guide](/running-tasks/webhooks-faq))
+2. **Webhooks** — Get notified when the task completes ([see webhooks guide](/going-to-production/webhooks))
The code below polls every 5 seconds until the task reaches a terminal state. Once complete, `run.output` contains the extracted data as a dictionary.
@@ -365,7 +365,7 @@ A browser window will open on your machine (if you chose headful mode). Recordin
Define a schema to get typed JSON output from your automations
@@ -379,14 +379,14 @@ A browser window will open on your machine (if you chose headful mode). Recordin
Chain multiple steps together for complex automations
Get notified when tasks complete instead of polling
diff --git a/docs/going-to-production/proxy-geolocation.mdx b/docs/going-to-production/proxy-geolocation.mdx
index e3c48ffc8..1cf178d50 100644
--- a/docs/going-to-production/proxy-geolocation.mdx
+++ b/docs/going-to-production/proxy-geolocation.mdx
@@ -221,6 +221,11 @@ export const COUNTRY_PATHS = {
export const PROXY_LOCATIONS = [
{ code: "US", name: "United States", value: "RESIDENTIAL", timezone: "America/New_York", flag: "🇺🇸" },
{ code: "US_ISP", name: "United States (ISP)", value: "RESIDENTIAL_ISP", timezone: "America/New_York", flag: "🇺🇸" },
+ { code: "US_CA", name: "California", value: "US-CA", timezone: "America/Los_Angeles", flag: "🇺🇸" },
+ { code: "US_NY", name: "New York", value: "US-NY", timezone: "America/New_York", flag: "🇺🇸" },
+ { code: "US_TX", name: "Texas", value: "US-TX", timezone: "America/Chicago", flag: "🇺🇸" },
+ { code: "US_FL", name: "Florida", value: "US-FL", timezone: "America/New_York", flag: "🇺🇸" },
+ { code: "US_WA", name: "Washington", value: "US-WA", timezone: "America/Los_Angeles", flag: "🇺🇸" },
{ code: "CA", name: "Canada", value: "RESIDENTIAL_CA", timezone: "America/Toronto", flag: "🇨🇦" },
{ code: "MX", name: "Mexico", value: "RESIDENTIAL_MX", timezone: "America/Mexico_City", flag: "🇲🇽" },
{ code: "AR", name: "Argentina", value: "RESIDENTIAL_AR", timezone: "America/Argentina/Buenos_Aires", flag: "🇦🇷" },
@@ -560,6 +565,11 @@ Use these enum values for country-level targeting. Each routes through a residen
|-------|---------|----------|
| `RESIDENTIAL` | United States | America/New_York |
| `RESIDENTIAL_ISP` | United States | America/New_York |
+| `US-CA` | California, US | America/Los_Angeles |
+| `US-NY` | New York, US | America/New_York |
+| `US-TX` | Texas, US | America/Chicago |
+| `US-FL` | Florida, US | America/New_York |
+| `US-WA` | Washington, US | America/Los_Angeles |
| `RESIDENTIAL_AR` | Argentina | America/Argentina/Buenos_Aires |
| `RESIDENTIAL_AU` | Australia | Australia/Sydney |
| `RESIDENTIAL_BR` | Brazil | America/Sao_Paulo |
@@ -722,7 +732,7 @@ Need a location that's not available? Get help in the [Skyvern Discord community
Maintain IP consistency across multi-step tasks
diff --git a/docs/going-to-production/webhooks.mdx b/docs/going-to-production/webhooks.mdx
index 370eb8159..574fe8192 100644
--- a/docs/going-to-production/webhooks.mdx
+++ b/docs/going-to-production/webhooks.mdx
@@ -6,7 +6,7 @@ slug: going-to-production/webhooks
Workflows and task runs are asynchronous. When you call `run_task` or `run_workflow`, the API returns immediately with a run ID, but the actual execution happens in the background and can take variable time.
-Instead of polling the `get_runs` endpoint, you can use Webhooks to get notified when they finish.
+Instead of polling the `get_runs` endpoint, you can use Webhooks to get notified when they finish. Webhooks fire only when a run reaches a terminal status: `completed`, `failed`, `terminated`, `timed_out`, or `canceled`.
This page covers setting them up, explains payload structure, signature verification, and handling delivery failures.
diff --git a/docs/images/cloud/credentials-2fa-push-form.png b/docs/images/cloud/credentials-2fa-push-form.png
new file mode 100644
index 000000000..4e93764cc
Binary files /dev/null and b/docs/images/cloud/credentials-2fa-push-form.png differ
diff --git a/docs/images/cloud/credentials-add-credit-card.png b/docs/images/cloud/credentials-add-credit-card.png
new file mode 100644
index 000000000..0c9f1bab5
Binary files /dev/null and b/docs/images/cloud/credentials-add-credit-card.png differ
diff --git a/docs/images/cloud/credentials-add-dropdown.png b/docs/images/cloud/credentials-add-dropdown.png
new file mode 100644
index 000000000..e1f8a48e9
Binary files /dev/null and b/docs/images/cloud/credentials-add-dropdown.png differ
diff --git a/docs/images/cloud/credentials-credit-card-detail.png b/docs/images/cloud/credentials-credit-card-detail.png
new file mode 100644
index 000000000..3beb0c6d3
Binary files /dev/null and b/docs/images/cloud/credentials-credit-card-detail.png differ
diff --git a/docs/images/cloud/credentials-sidebar-nav.png b/docs/images/cloud/credentials-sidebar-nav.png
new file mode 100644
index 000000000..c60ae31f8
Binary files /dev/null and b/docs/images/cloud/credentials-sidebar-nav.png differ
diff --git a/docs/multi-step-automations/file-operations.mdx b/docs/multi-step-automations/file-operations.mdx
index e5941ddb0..207095cbf 100644
--- a/docs/multi-step-automations/file-operations.mdx
+++ b/docs/multi-step-automations/file-operations.mdx
@@ -687,7 +687,7 @@ done
- **`file_url`** points to the file. Here, `{{ resume }}` is a workflow parameter passed at runtime — it could be a public URL, an S3 presigned URL, or a Google Drive link.
-- **`file_type`** tells Skyvern how to read the file. Use `pdf`, `csv`, or `excel`.
+- **`file_type`** tells Skyvern how to read the file. Use `csv`, `excel`, `pdf`, `image`, or `docx`.
- **`json_schema`** defines exactly what to extract. The LLM reads the PDF and returns data matching this structure. The `work_experience` array means you'll get one object per job with `company` and `role` fields.
The output is available as `{{ parse_resume_output }}` in subsequent blocks and looks like this:
@@ -708,7 +708,7 @@ Without a `json_schema`, you get the raw parsed content instead — plain text f
| Parameter | Type | Use this to |
|-----------|------|-------------|
| `file_url` | string | Point to the file (HTTP URL, S3 URI, or parameter like `{{ resume }}`) |
-| `file_type` | string | Specify format: `csv`, `excel`, or `pdf` |
+| `file_type` | string | Specify format: `csv`, `excel`, `pdf`, `image`, or `docx` |
| `json_schema` | object | Define the structure you want extracted |
**Supported sources for `file_url`:**
diff --git a/docs/optimization/browser-profiles.mdx b/docs/optimization/browser-profiles.mdx
index 2e49366c9..970a264ee 100644
--- a/docs/optimization/browser-profiles.mdx
+++ b/docs/optimization/browser-profiles.mdx
@@ -332,7 +332,7 @@ async def main():
# Run workflow with saved profile, no login needed
result = await client.run_workflow(
- workflow_id="wf_daily_metrics",
+ workflow_id="wpid_daily_metrics",
browser_profile_id="bp_490705123456789012",
wait_for_completion=True,
)
@@ -351,7 +351,7 @@ async function main() {
// Run workflow with saved profile, no login needed
const result = await client.runWorkflow({
body: {
- workflow_id: "wf_daily_metrics",
+ workflow_id: "wpid_daily_metrics",
browser_profile_id: "bp_490705123456789012",
},
waitForCompletion: true,
@@ -368,7 +368,7 @@ curl -X POST "https://api.skyvern.com/v1/run/workflows" \
-H "x-api-key: $SKYVERN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
- "workflow_id": "wf_daily_metrics",
+ "workflow_id": "wpid_daily_metrics",
"browser_profile_id": "bp_490705123456789012"
}'
```
@@ -381,7 +381,7 @@ curl -X POST "https://api.skyvern.com/v1/run/workflows" \
"run_id": "wr_494469342201718946",
"status": "created",
"run_request": {
- "workflow_id": "wf_daily_metrics",
+ "workflow_id": "wpid_daily_metrics",
"browser_profile_id": "bp_490705123456789012",
"proxy_location": "RESIDENTIAL"
}
diff --git a/docs/optimization/browser-sessions.mdx b/docs/optimization/browser-sessions.mdx
index f3c9293ca..8f96b1710 100644
--- a/docs/optimization/browser-sessions.mdx
+++ b/docs/optimization/browser-sessions.mdx
@@ -259,7 +259,7 @@ async def main():
# Then run a workflow in the same session (already logged in)
result = await client.run_workflow(
- workflow_id="wf_export_monthly_report",
+ workflow_id="wpid_export_monthly_report",
browser_session_id=session_id,
wait_for_completion=True,
)
@@ -295,7 +295,7 @@ async function main() {
// Then run a workflow in the same session (already logged in)
const result = await client.runWorkflow({
body: {
- workflow_id: "wf_export_monthly_report",
+ workflow_id: "wpid_export_monthly_report",
browser_session_id: sessionId,
},
waitForCompletion: true,
@@ -341,7 +341,7 @@ curl -s -X POST "https://api.skyvern.com/v1/run/workflows" \
-H "x-api-key: $SKYVERN_API_KEY" \
-H "Content-Type: application/json" \
-d "{
- \"workflow_id\": \"wf_export_monthly_report\",
+ \"workflow_id\": \"wpid_export_monthly_report\",
\"browser_session_id\": \"$SESSION_ID\"
}"
@@ -583,7 +583,7 @@ await client.run_task(prompt="Step 1", browser_session_id=session.browser_sessio
await client.run_task(prompt="Step 2", browser_session_id=session.browser_session_id, wait_for_completion=True)
# More efficient: single workflow (blocks share one browser, no inter-task overhead)
-await client.run_workflow(workflow_id="wf_abc", wait_for_completion=True)
+await client.run_workflow(workflow_id="wpid_abc", wait_for_completion=True)
```
```typescript TypeScript
@@ -593,7 +593,7 @@ await client.runTask({ body: { prompt: "Step 1", browser_session_id: session.bro
await client.runTask({ body: { prompt: "Step 2", browser_session_id: session.browser_session_id }, waitForCompletion: true });
// More efficient: single workflow (blocks share one browser, no inter-task overhead)
-await client.runWorkflow({ body: { workflow_id: "wf_abc" }, waitForCompletion: true });
+await client.runWorkflow({ body: { workflow_id: "wpid_abc" }, waitForCompletion: true });
```
diff --git a/docs/running-automations/task-parameters.mdx b/docs/running-automations/task-parameters.mdx
index 36c5d10b3..032d41e70 100644
--- a/docs/running-automations/task-parameters.mdx
+++ b/docs/running-automations/task-parameters.mdx
@@ -32,6 +32,7 @@ Only `prompt` is a required parameter.
| [`max_screenshot_scrolls`](#max_screenshot_scrolls) | integer | Capture lazy-loaded content in screenshots |
| [`browser_address`](#browser_address) | string | Connect to your own browser for local development |
| [`include_action_history_in_verification`](#include_action_history_in_verification) | boolean | Improve verification accuracy for multi-step forms |
+| [`run_with`](#run_with) | string | Choose whether to run with the AI agent or generated code |
| [`model`](#model) | object | Configure model settings (e.g., temperature) |
---
@@ -296,6 +297,11 @@ Use this for geo-restricted content or to reduce bot detection.
| `RESIDENTIAL_KR` | South Korea |
| `RESIDENTIAL_TR` | Turkey |
| `RESIDENTIAL_ISP` | ISP proxy |
+| `US-CA` | California, US |
+| `US-NY` | New York, US |
+| `US-TX` | Texas, US |
+| `US-FL` | Florida, US |
+| `US-WA` | Washington, US |
| `NONE` | No proxy |
@@ -326,7 +332,7 @@ curl -X POST "https://api.skyvern.com/v1/run/tasks" \
```
-**Granular targeting (US states/cities):**
+**Granular targeting (state/city level):**
```python Python
@@ -755,6 +761,45 @@ curl -X POST "https://api.skyvern.com/v1/run/tasks" \
---
+## `run_with`
+
+Choose whether the task runs with the AI agent or generated code.
+
+| Value | Description |
+|-------|-------------|
+| `agent` | Run with the AI agent (default). The agent analyzes screenshots and decides actions in real time. |
+| `code` | Run with generated code. Faster and more deterministic, but requires a previously published workflow. |
+
+
+```python Python
+result = await client.run_task(
+ prompt="Fill out the contact form",
+ run_with="agent"
+)
+```
+
+```typescript TypeScript
+const result = await client.runTask({
+ body: {
+ prompt: "Fill out the contact form",
+ run_with: "agent",
+ },
+});
+```
+
+```bash cURL
+curl -X POST "https://api.skyvern.com/v1/run/tasks" \
+ -H "x-api-key: $SKYVERN_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "prompt": "Fill out the contact form",
+ "run_with": "agent"
+ }'
+```
+
+
+---
+
## `model`
Optional model configuration for the task.
diff --git a/docs/sdk-reference/overview.mdx b/docs/sdk-reference/overview.mdx
index 8c13ec39e..a70112178 100644
--- a/docs/sdk-reference/overview.mdx
+++ b/docs/sdk-reference/overview.mdx
@@ -54,7 +54,7 @@ If you're inside a framework that already runs an event loop (FastAPI, Django AS
## Environments
-The SDK ships with two built-in environment URLs:
+The SDK ships with three built-in environment URLs:
```python
from skyvern.client import SkyvernEnvironment
@@ -63,6 +63,7 @@ from skyvern.client import SkyvernEnvironment
| Environment | URL | When to use |
|-------------|-----|-------------|
| `SkyvernEnvironment.CLOUD` | `https://api.skyvern.com` | Skyvern Cloud (default) |
+| `SkyvernEnvironment.STAGING` | `https://api.staging.skyvern.com` | Staging environment for testing |
| `SkyvernEnvironment.LOCAL` | `http://localhost:8000` | Local server started with `skyvern run server` |
For a self-hosted instance at a custom URL, pass `base_url` instead:
diff --git a/docs/self-hosted/docker.mdx b/docs/self-hosted/docker.mdx
index 320ab8dd5..9461fc4d5 100644
--- a/docs/self-hosted/docker.mdx
+++ b/docs/self-hosted/docker.mdx
@@ -194,7 +194,7 @@ VIDEO_PATH=./videos
```bash
# Maximum steps before a task times out
-MAX_STEPS_PER_RUN=50
+MAX_STEPS_PER_RUN=10
# Server port
PORT=8000
diff --git a/docs/self-hosted/kubernetes.mdx b/docs/self-hosted/kubernetes.mdx
index 567f16f8d..ca20c3b1c 100644
--- a/docs/self-hosted/kubernetes.mdx
+++ b/docs/self-hosted/kubernetes.mdx
@@ -77,7 +77,7 @@ stringData:
# Browser settings
BROWSER_TYPE: "chromium-headless"
BROWSER_ACTION_TIMEOUT_MS: "5000"
- MAX_STEPS_PER_RUN: "50"
+ MAX_STEPS_PER_RUN: "10"
# Server
PORT: "8000"
diff --git a/docs/self-hosted/llm-configuration.mdx b/docs/self-hosted/llm-configuration.mdx
index c49ec7f1d..20ee10fc5 100644
--- a/docs/self-hosted/llm-configuration.mdx
+++ b/docs/self-hosted/llm-configuration.mdx
@@ -108,7 +108,21 @@ The `AZURE_DEPLOYMENT` is the name you chose when deploying the model, not the m
## Google Gemini
-Gemini models through [Vertex AI](https://cloud.google.com/vertex-ai). Requires a GCP project with Vertex AI enabled.
+Skyvern supports Gemini through two paths: the **Gemini API** (simpler, uses an API key) and **Vertex AI** (enterprise, uses a GCP service account).
+
+### Gemini API
+
+The quickest way to use Gemini. Get an API key from [Google AI Studio](https://aistudio.google.com/).
+
+```bash .env
+ENABLE_GEMINI=true
+GEMINI_API_KEY=your-gemini-api-key
+LLM_KEY=VERTEX_GEMINI_2.5_FLASH
+```
+
+### Vertex AI
+
+For enterprise deployments through [Vertex AI](https://cloud.google.com/vertex-ai). Requires a GCP project with Vertex AI enabled.
```bash .env
ENABLE_VERTEX_AI=true
@@ -118,7 +132,7 @@ GCP_PROJECT_ID=your-gcp-project-id
GCP_REGION=us-central1
```
-### Setup steps
+**Vertex AI setup steps:**
1. Create a [GCP project](https://console.cloud.google.com/) with billing enabled
2. Enable the **Vertex AI API** in your project
diff --git a/docs/self-hosted/overview.mdx b/docs/self-hosted/overview.mdx
index 526bff066..047c3e111 100644
--- a/docs/self-hosted/overview.mdx
+++ b/docs/self-hosted/overview.mdx
@@ -13,26 +13,23 @@ Self-hosted Skyvern has four components running on your infrastructure:
```mermaid
flowchart LR
subgraph Your Infrastructure
- API[Skyvern API Server]
+ API[Skyvern API Server
+ Embedded Browser]
DB[(PostgreSQL)]
- Browser[Browser Container]
end
LLM[LLM Provider]
Sites[Target Websites]
API <--> DB
- API <--> Browser
API <--> LLM
- Browser <--> Sites
+ API <--> Sites
```
| Component | Role |
|-----------|------|
-| **Skyvern API Server** | Orchestrates tasks, processes LLM responses, stores results |
+| **Skyvern API Server** | Orchestrates tasks, processes LLM responses, stores results. Includes an embedded Playwright-managed Chromium browser that executes web automation. |
| **PostgreSQL** | Stores task history, workflows, credentials, and organization data |
-| **Browser Container** | Playwright-managed Chromium that executes the actual web automation |
-| **LLM Provider** | Analyzes screenshots and determines actions. You provide the API key (OpenAI, Anthropic, Azure, or local via Ollama) |
+| **LLM Provider** | Analyzes screenshots and determines actions. You provide the API key (OpenAI, Anthropic, Azure OpenAI, Google Vertex AI, Amazon Bedrock, Groq, OpenRouter, or local via Ollama) |
### How a task executes