.env. This page covers LLM providers, browser settings, credentials and encryption, other server settings, storage and Kubernetes. For setup, start at Self-host.
Skyvern uses LLMs to analyze screenshots and decide what actions to take. Configure at least one LLM provider before running tasks.
How Skyvern uses LLMs
Skyvern makes multiple LLM calls per task step:- Screenshot analysis: Identify interactive elements on the page
- Action planning: Decide what to click, type, or extract
- Result extraction: Parse data from the page into structured output
LLM_KEY. Skyvern also supports a SECONDARY_LLM_KEY for lighter tasks to reduce costs.
Quick Start Recommendations
Best models for production (2026):OpenAI
The most common choice. Requires an API key from platform.openai.com..env
Available models
Optional settings
.env
xAI Grok
Grok models from x.ai. Requires an xAI API key..env
Available models
Optional settings
.env
Anthropic
Claude models from anthropic.com..env
Available models
Azure OpenAI
Microsoft-hosted OpenAI models. Requires an Azure subscription with OpenAI service provisioned..env
Setup steps
- Create an Azure OpenAI resource in the Azure Portal
- Open the Azure AI Foundry portal from your resource’s overview page
- Go to Shared Resources → Deployments
- Click Deploy Model → Deploy Base Model → select GPT-4o or GPT-4
- Note the Deployment Name. Use this for
AZURE_DEPLOYMENT - Copy your API key and endpoint from the Azure Portal
The
AZURE_DEPLOYMENT is the name you chose when deploying the model, not the model name itself.Google Gemini
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..env
Available Gemini API models
Vertex AI
For enterprise deployments through Vertex AI. Requires a GCP project with Vertex AI enabled..env
If you’re migrating from an older Skyvern version,
VERTEX_LOCATION replaces the previous GCP_REGION variable. Update your .env accordingly.- Create a GCP project with billing enabled
- Enable the Vertex AI API in your project
- Create a service account with the Vertex AI User role
- Download the service account JSON key file
- Set
VERTEX_CREDENTIALSto the contents of that file as a JSON string. If you leave it unset, Skyvern falls back to Application Default Credentials (for exampleGOOGLE_APPLICATION_CREDENTIALSor Workload Identity)
For global endpoint access, set
VERTEX_LOCATION=global and ensure VERTEX_PROJECT_ID is set. Not all models support the global endpoint.Available Vertex AI models
Amazon Bedrock
Run Anthropic Claude through your AWS account..env
Setup steps
- Create an IAM user with
AmazonBedrockFullAccesspolicy - Generate access keys for the IAM user
- In the Bedrock console, go to Model Access
- Enable access to Claude Opus 4.7
Available models
Bedrock inference profile keys (
*_INFERENCE_PROFILE) use cross-region inference and require AWS_REGION only. No access keys needed if running on an IAM-authenticated instance.VolcEngine (ByteDance Doubao)
VolcEngine provides access to ByteDance’s Doubao models with vision support..env
Available models
Optional settings
.env
Novita
Novita AI provides access to DeepSeek, Llama, and other open-source models..env
Available models
Moonshot
Moonshot AI provides the Kimi series models with long context support..env
Available models
Optional settings
.env
Inception
Inception AI provides the Mercury series models..env
Available models
Optional settings
.env
Ollama (Local Models)
Run open-source models locally with Ollama. No API costs, but requires sufficient local compute..env
Setup steps
- Install Ollama
- Pull a model:
ollama pull gemma4 - Start Ollama:
ollama serve - Configure Skyvern to connect
Docker networking
When running Skyvern in Docker and Ollama on the host:OpenAI-Compatible Endpoints
Connect to any service that implements the OpenAI API format, including LiteLLM, LocalAI, vLLM, and text-generation-inference..env
This is useful for:
- Running local models with a unified API
- Using LiteLLM as a proxy to switch between providers
- Connecting to self-hosted inference servers
OpenRouter
Access multiple models through a single API at openrouter.ai..env
Groq
Inference on open-source models at groq.com..env
Groq specializes in fast inference for open-source models. Response times are typically much faster than other providers, but model selection is limited.
Using multiple models
Primary and secondary models
Configure a cheaper model for lightweight operations:.env
Task-specific models
For fine-grained control, you can override models for specific operations:.env
LLM_KEY and SECONDARY_LLM_KEY.
Troubleshooting
”To enable svg shape conversion, please set the Secondary LLM key”
Some operations require a secondary model. SetSECONDARY_LLM_KEY in your environment:
.env
“Context window exceeded”
The page content is too large for the model’s context window. Options:- Use a model with larger context support (GPT-5.5, Gemini 2.5 Pro, or Claude 4.7 Opus)
- Simplify your prompt to require less page analysis
- Start from a more specific URL with less content
”Environment variables LLM_API_KEY are required for LLMProvider …”
The configuredLLM_KEY doesn’t match any enabled provider, so Skyvern treats it as a generic model name and asks for LLM_API_KEY. Verify:
- The provider is enabled (
ENABLE_OPENAI=true, etc.) - The
LLM_KEYvalue matches a supported model name exactly - Model names are case-sensitive:
OPENAI_GPT5_5notopenai_gpt5_5
Container logs show authentication errors
Check your API key configuration:- Ensure the key is set correctly without extra whitespace
- Verify the key hasn’t expired or been revoked
- For Azure, ensure
AZURE_API_BASEincludes the full URL withhttps://
Slow response times
LLM calls typically take 2-10 seconds. Longer times may indicate:- Network latency to the provider
- Rate limiting (the provider may be throttling requests)
- For Ollama, insufficient local compute resources
Browser settings
Set these in.env (or the backend secret on Kubernetes) and restart the server. For the choice between headful, headless and cdp-connect, see Self-host.
Match
BROWSER_LOCALE and BROWSER_TIMEZONE to the region the site expects. A mismatch can trigger bot detection.
Each concurrent run uses its own browser. Approximate memory:
On out-of-memory errors, lower
BROWSER_MAX_PAGES_NUMBER, shrink the viewport, switch to chromium-headless, or run fewer runs at once.
Connect your own Chrome (CDP)
Start your installed Chrome. Set
BROWSER_TYPE=cdp-connect and CHROME_EXECUTABLE_PATH. Skyvern copies your profile to ./tmp/user_data_dir, launches Chrome with remote debugging on port 9222, and connects. Close every Chrome window first; if Chrome is already running, Skyvern returns an error. If port 9222 is already in use, Skyvern connects to that instance instead.
Connect to a Chrome that is already running. In Chrome, open
chrome://inspect/#remote-debugging and turn on remote debugging. Skyvern auto-discovers a local debugging server, or accepts a pasted ws://.../devtools/browser/... URL. skyvern init browser walks you through it.
If Skyvern runs in Docker and can’t reach Chrome’s loopback listener, start a separate profile on a reachable address. Since Chrome 136, --remote-debugging-port is ignored for the default profile, so always pass --user-data-dir:
If Chrome rejects the
host.docker.internal host name, Skyvern retries with the Docker host gateway IPv4 address.
On Windows with Docker Desktop, the chrome://inspect listener is loopback only. From an Administrator PowerShell in the Skyvern repo, run .\scripts\windows_chrome_inspect_cdp.ps1 -UpdateEnv, then docker compose up -d --force-recreate skyvern. The helper proxies 0.0.0.0:9223 to Chrome, adds a firewall rule, and writes BROWSER_REMOTE_DEBUGGING_URL=ws://host.docker.internal:9223/devtools/browser/<id> and BROWSER_REMOTE_DEBUGGING_HOST_HEADER to .env. Click Allow if Chrome asks to allow the connection. If Windows Firewall blocks port 9222 for a classic endpoint:
curl http://localhost:9222/json/version. It returns Chrome’s version and a webSocketDebuggerUrl.
Credentials and encryption
CREDENTIAL_VAULT_TYPE picks where new credentials are stored. Restart the server after changing it.
Bitwarden and Vaultwarden
Skyvern doesn’t call Bitwarden directly. It talks to a Bitwarden CLI server (bw serve), which is logged in to your vault and unlocked.
Self-hosted Vaultwarden. The open-source
docker-compose.yml ships two commented-out services: vaultwarden (the server, on 127.0.0.1:11002) and bitwarden-cli (built from bitwarden-cli-server/). To use them:
-
Uncomment
vaultwarden, start it, sign up, and create your master password and an organization. Then setSIGNUPS_ALLOWED: "false". - In Vaultwarden, copy the API client ID and secret.
-
Uncomment
bitwarden-cliand set its environment. It runsbw config server, logs in with the API key, unlocks, and serves on port8087, published as127.0.0.1:8002. -
Set
CREDENTIAL_VAULT_TYPE=bitwardenand theSKYVERN_AUTH_BITWARDEN_*values on the Skyvern server (same API key and password). PointBITWARDEN_SERVERat the CLI server:http://localhostand port8002from the host, orhttp://bitwarden-cliand port8087from another container in the same Compose project. -
Check it:
curl http://localhost:8002/statusreturns the vault status.
Encryption at rest
WithENABLE_ENCRYPTION=true, Skyvern encrypts stored secrets such as organization tokens and OAuth refresh tokens. The Google integrations require it.
Other server settings
URL validation
URL validation is off by default, so Skyvern can open, fetch and call internal hosts without extra setup. That includes an intranet portal, a service on your network andlocalhost. Set ENABLE_URL_VALIDATION=true if people you don’t trust can start tasks or workflows on your server, or if it runs next to internal services or a cloud metadata endpoint.
When it is on, Skyvern refuses a URL if its host is localhost, a name ending in .local, .localhost, .internal, .svc or .cluster.local, or an address in a loopback, private (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), link-local (169.254.0.0/16, which includes the cloud metadata address), shared (100.64.0.0/10), reserved, multicast or unspecified range. Names are checked after DNS resolution, so a public name that resolves to a private address is refused too. The check covers the URLs a run or workflow gives Skyvern: page navigation and link clicks, downloads, webhooks, 2FA callbacks, and SFTP, SMTP and S3-compatible endpoints. SFTP, SMTP and S3 targets also have their own ALLOW_SFTP_INTERNAL_HOSTS, ALLOW_SMTP_INTERNAL_HOSTS and ALLOW_S3_ENDPOINT_INTERNAL_HOSTS switches (the S3 one also allows plain http:// endpoints).
With validation on, list the hosts you want to keep reachable in ALLOWED_HOSTS, a JSON list of exact host names or IP addresses such as ALLOWED_HOSTS=["intranet.example.com"]. BLOCKED_HOSTS adds hosts to refuse.
Storage
SKYVERN_STORAGE_TYPE picks where artifacts go.
Each cloud backend uses four buckets (containers on Azure). The defaults are
skyvern-artifacts, skyvern-screenshots, skyvern-browser-sessions and skyvern-uploads.
Docker Compose mounts
./artifacts, ./videos, ./har and ./log next to docker-compose.yml. Local storage isn’t shared between servers and is never cleaned up; delete old files yourself, for example find ./artifacts -type f -mtime +30 -delete.
AWS S3
.env
AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, an IAM role on EC2, ECS or EKS, or AWS_PROFILE set in the container’s environment.
Create the buckets first. Bucket names are global, so add a unique prefix.
AWS_REGION matches the bucket region.
Azure Blob Storage
.env
Google Cloud Storage
.env
GOOGLE_APPLICATION_CREDENTIALS pointing at a service-account key. Create the buckets first.
Move existing local artifacts
ChangingSKYVERN_STORAGE_TYPE only affects new artifacts. To copy old ones, sync them once, then switch and restart:
docker compose logs skyvern | grep -i storage.
Kubernetes
The manifests inkubernetes-deployment/ create a skyvern namespace with postgres, skyvern-backend (API and browser, port 8000) and skyvern-frontend (UI on 8080, artifacts on 9090), plus a Traefik ingress routing /api to the backend, /artifacts to 9090 and / to the UI. Any ingress controller works; change ingressClassName.
After
./k8s-deploy.sh, wait for the backend pod to show 1/1 (migrations take 1–2 minutes), then read the API key and give it to the UI:
hostPath volumes, which only work on a single node. For production, replace them with PVCs in backend/backend-deployment.yaml, or use S3, Azure Blob or GCS:
replicas on the backend deployment to run more pods; each runs its own browser. With more than one pod, storage must be shared (S3, Azure Blob, GCS or ReadWriteMany volumes). Give each backend pod at least 2 GB:
tls section in ingress.yaml and create the secret (or use cert-manager), then switch the frontend URLs to https:// and wss://:
postgres/ manifests and set DATABASE_STRING: "postgresql+psycopg://user:password@your-db-host:5432/skyvern" in the backend secret.
The manifests have no authentication. Add it at the ingress, or keep the cluster off the public internet.
kubectl delete namespace skyvern removes everything.
