emulate
This skill runs local emulated APIs for 14+ third-party services including Vercel, GitHub, Google, Slack, AWS, Stripe, and others.
Identity proven by GitHub's verified organisation badge (vercel, vercel-labs)
- Agents
- Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode, claude.ai and API
- License
- Apache-2.0 (permissive)
- Pin
- c77cb73pinned Oct 9, 2026
- Context cost
- about 4,700 tokenswhen the skill loads
- GitHub stars
- 1,880on vercel-labs/emulate
- Scripts
- None found
What it does
“Local drop-in API emulator for Vercel, GitHub, Google, Slack, Apple, Microsoft, AWS, Clerk, Linear, Twilio, and other developer APIs. Use when the user needs to start emulated services, configure seed data, write tests against local APIs, set up CI without network access, or work with the emulate CLI or programmatic API. Triggers include "start the emulator", "emulate services", "mock API locally", "create emulator config", "test against local API", "npx emulate", or any task requiring local service emulation.”
Generated summary from the skill's own text
This skill runs local emulated APIs for 14+ third-party services including Vercel, GitHub, Google, Slack, AWS, Stripe, and others. The agent can start emulated services, seed test data from configuration files, and point applications to these local endpoints instead of real APIs. It supports both CLI-based startup and programmatic integration for testing, CI/CD, and offline development.
When to use it
- Testing OAuth flows and API integrations without network access
- Setting up CI pipelines that require multiple mocked third-party services
- Writing tests against production-fidelity local API emulators
- Developing locally without credentials or external service dependencies
When not to
- When real API behavior diverges from emulator implementation requirements
- Testing features requiring actual email delivery or external side effects
Install
These commands install from the publisher's repository and need no account.
skills CLI
npx skills add vercel-labs/emulate --skill emulateInstalls from the repository's default branch, which may have changed since the commit we checked.
GitHub CLI 2.90 or later
gh skill install vercel-labs/emulate emulate@c77cb73e7ab525c5260dd36c04c91a54a23e7e75Installs the commit we checked (c77cb73).
Copy by hand
Download the folder at c77cb73 and put it in .claude/skills/emulate for Claude Code and in .agents/skills/emulate for Codex, Cursor, Gemini CLI, GitHub Copilot and OpenCode.
Claude Code plugin
/plugin install vercel@claude-plugins-officialThe publisher's plugin in Claude's official marketplace. It may hold more than this skill, and we have not pinned it.
Copy for your agent
A prompt for any coding agent. It installs this skill from GitHub at the pinned commit, copies the files as they are, and runs nothing unless you ask.
Prompt
Install the agent skill "emulate" by Vercel. Source, pinned to commit c77cb73e7ab525c5260dd36c04c91a54a23e7e75: https://github.com/vercel-labs/emulate/tree/c77cb73e7ab525c5260dd36c04c91a54a23e7e75/skills/emulate 1. Download that folder at exactly this commit. Do not use the default branch. 2. Copy every file unchanged, keeping the folder structure, into .claude/skills/emulate/ for Claude Code and .agents/skills/emulate/ for Codex, Cursor, Gemini CLI, GitHub Copilot and OpenCode. Create the folders if they do not exist. 3. Do not edit the files, and do not run any script in the folder unless I ask you to. 4. When you are done, list the files you copied and where you put them. Listing and checks: https://www.agentnative.dev/skills/vercel/emulate
SKILL.md at the pin
---
name: emulate
description: Local drop-in API emulator for Vercel, GitHub, Google, Slack, Apple, Microsoft, AWS, Clerk, Linear, Twilio, and other developer APIs. Use when the user needs to start emulated services, configure seed data, write tests against local APIs, set up CI without network access, or work with the emulate CLI or programmatic API. Triggers include "start the emulator", "emulate services", "mock API locally", "create emulator config", "test against local API", "npx emulate", or any task requiring local service emulation.
allowed-tools: Bash(npx emulate:*)
---
# Service Emulation with emulate
Local drop-in replacement services for CI and no-network sandboxes. Fully stateful, production-fidelity API emulation, not mocks.
## Quick Start
```bash
npx emulate
```
All services listen on IPv4 loopback (`127.0.0.1`) by default:
| Service | Default Port |
|-----------|-------------|
| Vercel | 4000 |
| GitHub | 4001 |
| Google | 4002 |
| Slack | 4003 |
| Apple | 4004 |
| Microsoft | 4005 |
| Okta | 4006 |
| AWS | 4007 |
| Resend | 4008 |
| Stripe | 4009 |
| MongoDB Atlas | 4010 |
| Clerk | 4011 |
| Linear | 4012 |
| Twilio | 4013 |
## CLI
```bash
# Start all services (zero-config)
npx emulate
# Start specific services
npx emulate --service vercel,github
# Custom base port (auto-increments per service)
npx emulate --port 3000
# Use a seed config file
npx emulate --seed config.yaml
# Generate omitted service secrets into a private file
npx emulate start --seed config.yaml --generated-secrets-file .emulate-secrets.json
# Generate a starter config
npx emulate init
# Generate config for a specific service
npx emulate init --service vercel
# List available services
npx emulate list
```
### Options
| Flag | Default | Description |
|------|---------|-------------|
| `-p, --port` | `4000` | Base port (auto-increments per service) |
| `--host` | `127.0.0.1` | Listening address; use `0.0.0.0` to allow network access |
| `-s, --service` | all | Comma-separated services to enable |
| `--seed` | auto-detect | Path to seed config (YAML or JSON) |
| `--base-url` | none | Override advertised base URL (supports `{service}` template) |
| `--portless` | off | Serve over HTTPS via portless (auto-registers aliases) |
| `--generated-secrets-file` | none | Generate omitted service secrets and write them to a new owner-only JSON file |
The port can also be set via `EMULATE_PORT` or `PORT` environment variables.
For access from a container or another machine, use `npx emulate start --host 0.0.0.0`. Set `--base-url` to a URL reachable by those clients when using OAuth redirects or other advertised URLs.
The generated-secrets destination must not exist. emulate removes inherited ACLs, verifies effective owner-only access, and publishes complete JSON before opening listeners or configuring portless. Handled startup failures remove the invocation-owned artifact. A hard termination can leave a complete artifact that must be removed manually after confirming no invocation is using it. Only service-generated values appear in the artifact. Linux requires `setfacl` and `getfacl` from the `acl` package. The flag fails closed when access controls cannot be verified and is not supported on Windows.
The advertised base URL (used in OAuth redirects, webhook URLs, etc.) can be overridden via `--base-url`, the `EMULATE_BASE_URL` env var (supports `{service}` template), or per-service `baseUrl` in the seed config. When running under portless, the `PORTLESS_URL` env var is also detected automatically.
## Programmatic API
```bash
npm install emulate
```
Each call to `createEmulator` starts a single service:
```typescript
import { createEmulator } from 'emulate'
const github = await createEmulator({ service: 'github', port: 4001 })
const vercel = await createEmulator({ service: 'vercel', port: 4002 })
github.url // 'http://localhost:4001'
vercel.url // 'http://localhost:4002'
await github.close()
await vercel.close()
```
For GitHub App tests, inspect secret-free minted installation-token metadata at `GET /_emulate/installation-tokens`.
### Options
| Option | Default | Description |
|--------|---------|-------------|
| `service` | *(required)* | `'vercel'`, `'github'`, `'google'`, `'slack'`, `'apple'`, `'microsoft'`, `'okta'`, `'aws'`, `'resend'`, `'stripe'`, `'mongoatlas'`, `'clerk'`, `'linear'`, or `'twilio'` |
| `port` | `4000` | Port for the HTTP server |
| `hostname` | `127.0.0.1` | Listening address for built-in and custom emulators |
| `seed` | none | Inline seed data (same shape as YAML config) |
| `baseUrl` | none | Override advertised base URL. Per-service `baseUrl` in seed config takes highest priority, then this option, then `EMULATE_BASE_URL` env var (supports `{service}`), then `PORTLESS_URL` (supports `{service}`, automatically set by the `portless` CLI wrapper), then `http://localhost:<port>`. |
Use `hostname: '0.0.0.0'` to allow connections from containers or other machines, and `baseUrl` to advertise a URL reachable by those clients.
### Instance Methods
| Method | Description |
|--------|-------------|
| `url` | Base URL of the running server |
| `reset()` | Wipe the store and replay seed data |
| `close()` | Shut down the HTTP server, returns a Promise |
## Vitest / Jest Setup
```typescript
import { createEmulator, type Emulator } from 'emulate'
let github: Emulator
let vercel: Emulator
beforeAll(async () => {
;[github, vercel] = await Promise.all([
createEmulator({ service: 'github', port: 4001 }),
createEmulator({ service: 'vercel', port: 4002 }),
])
process.env.GITHUB_EMULATOR_URL = github.url
process.env.VERCEL_EMULATOR_URL = vercel.url
})
afterEach(() => { github.reset(); vercel.reset() })
afterAll(() => Promise.all([github.close(), vercel.close()]))
```
## Configuration
Configuration is optional. The CLI auto-detects config files in this order:
1. `emulate.config.yaml` / `.yml`
2. `emulate.config.json`
3. `service-emulator.config.yaml` / `.yml`
4. `service-emulator.config.json`
Or pass `--seed <file>` explicitly. Run `npx emulate init` to generate a starter file.
### Config Structure
```yaml
tokens:
my_token:
login: admin
scopes: [repo, user]
vercel:
users:
- username: developer
name: Developer
email: dev@example.com
teams:
- slug: my-team
name: My Team
projects:
- name: my-app
team: my-team
framework: nextjs
integrations:
- client_id: oac_abc123
client_secret: secret_abc123
name: My Vercel App
redirect_uris:
- http://localhost:3000/api/auth/callback/vercel
github:
users:
- login: octocat
name: The Octocat
email: octocat@github.com
orgs:
- login: my-org
name: My Organization
members:
- login: octocat
role: admin
repos:
- owner: octocat
name: hello-world
language: JavaScript
auto_init: true
oauth_apps:
- client_id: Iv1.abc123
client_secret: secret_abc123
name: My Web App
redirect_uris:
- http://localhost:3000/api/auth/callback/github
google:
users:
- email: testuser@example.com
name: Test User
oauth_clients:
- client_id: my-client-id.apps.googleusercontent.com
client_secret: GOCSPX-secret
redirect_uris:
- http://localhost:3000/api/auth/callback/google
slack:
team:
name: My Workspace
domain: my-workspace
users:
- name: developer
real_name: Developer
email: dev@example.com
channels:
- name: general
topic: General discussion
bots:
- name: my-bot
oauth_apps:
- client_id: "12345.67890"
client_secret: example_client_secret
name: My Slack App
redirect_uris:
- http://localhost:3000/api/auth/callback/slack
signing_secret: my_signing_secret
linear:
organization:
name: Acme
url_key: acme
users:
- email: admin@example.com
name: Admin User
admin: true
- email: dev@example.com
name: Developer
teams:
- key: ENG
name: Engineering
states:
- name: Backlog
type: backlog
- name: Todo
type: unstarted
- name: In Progress
type: started
- name: Done
type: completed
labels:
- name: Bug
color: "#d92d20"
team: ENG
- name: Feature
color: "#2563eb"
team: ENG
issues:
- team: ENG
title: Fix local checkout test
description: Reproduce and fix the checkout failure.
state: Todo
assignee: dev@example.com
labels: [Bug]
oauth_apps:
- client_id: lin_example_client_id
client_secret: example_client_secret
name: My Linear App
redirect_uris:
- http://localhost:3000/api/auth/callback/linear
scopes: [read, write, issues:create, comments:create]
actor: user
tokens:
- token: lin_test_admin
user: admin@example.com
scopes: [read, write, issues:create, comments:create, admin]
strict_scopes: false
apple:
users:
- email: testuser@icloud.com
name: Test User
oauth_clients:
- client_id: com.example.app
team_id: TEAM001
name: My Apple App
redirect_uris:
- http://localhost:3000/api/auth/callback/apple
microsoft:
users:
- email: testuser@outlook.com
name: Test User
oauth_clients:
- client_id: example-client-id
client_secret: example-client-secret
name: My Microsoft App
redirect_uris:
- http://localhost:3000/api/auth/callback/microsoft-entra-id
aws:
region: us-east-1
s3:
buckets:
- name: my-app-bucket
sqs:
queues:
- name: my-app-events
iam:
users:
- user_name: developer
create_access_key: true
roles:
- role_name: lambda-execution-role
description: Role for Lambda function execution
okta:
users:
- login: testuser@okta.local
email: testuser@okta.local
first_name: Test
last_name: User
groups:
- name: Everyone
description: All users
type: BUILT_IN
okta_id: 00g_everyone
authorization_servers:
- id: default
name: default
audiences: [api://default]
oauth_clients:
- client_id: okta-test-client
client_secret: okta-test-secret
name: Sample OIDC Client
redirect_uris:
- http://localhost:3000/callback
auth_server_id: default
resend:
domains:
- name: example.com
region: us-east-1
contacts:
- email: test@example.com
first_name: Test
last_name: User
stripe:
customers:
- email: test@example.com
name: Test Customer
products:
- name: Pro Plan
description: Monthly pro subscription
prices:
- product_name: Pro Plan
currency: usd
unit_amount: 2000
mongoatlas:
projects:
- name: Project0
clusters:
- name: Cluster0
project: Project0
database_users:
- username: admin
project: Project0
databases:
- cluster: Cluster0
name: test
collections: [items]
clerk:
users:
- first_name: Test
last_name: User
email_addresses: [test@example.com]
password: clerk_test_password
organizations:
- name: My Company
slug: my-company
members:
- email: test@example.com
role: admin
oauth_applications:
- client_id: clerk_emulate_client
client_secret: clerk_emulate_secret
name: Emulate App
redirect_uris:
- http://localhost:3000/api/auth/callback/clerk
twilio:
account:
sid: AC00000000000000000000000000000000
auth_token: twilio_test_auth_token
friendly_name: Local Twilio Account
api_keys:
- sid: SK00000000000000000000000000000000
secret: twilio_test_api_secret
friendly_name: Local API Key
phone_numbers:
- phone_number: "+15551234567"
friendly_name: Local SMS and Voice Number
sms_url: http://localhost:3000/api/twilio/sms
voice_url: http://localhost:3000/api/twilio/voice
messaging_services:
- friendly_name: Local Messaging Service
phone_numbers: ["+15551234567"]
verify_services:
- friendly_name: Local Verify Service
code: "123456"
default_channel: sms
conversations:
services:
- friendly_name: Local Conversations
```
`slack.signing_secret` signs every outbound event subscription callback. Signed callbacks include `X-Slack-Request-Timestamp` and `X-Slack-Signature`, calculated as `v0=<HMAC-SHA256(secret, "v0:<timestamp>:<raw-body>")>` over the exact serialized callback body. Configure the receiver with the same secret and verify the unparsed request body. Callbacks are unsigned when the secret is absent or empty.
GitHub App `private_key` values are intentionally omitted from starter configuration. Programmatic `createEmulator` calls generate an RSA key and expose it through `generatedSecrets`. CLI startup generates omitted keys only when `--generated-secrets-file <path>` is provided; otherwise the seed must contain an explicit, valid private key. Never use a placeholder PEM value.
GitHub organization `members` are optional. Entries reference seeded users by `login`; `role` defaults to `member`, while `admin` creates an organization administrator. Unknown users are ignored.
### Auth
Tokens map to users. Pass them as `Authorization: Bearer <token>` or `Authorization: token <token>`. When no tokens are configured, a default `test_token_admin` is created for the `admin` user.
Each service also has a fallback user. If no token is provided, requests authenticate as the first seeded user.
## HTTPS with portless
[portless](https://github.com/vercel-labs/portless) gives emulators trusted HTTPS URLs with auto-generated certs. Use the `--portless` flag to auto-register each service as a portless alias:
```bash
npx emulate start --portless
# github https://github.emulate.localhost
# google https://google.emulate.localhost
# ...
```
This requires the portless proxy to be running (`portless proxy start`). If portless is not installed, emulate will prompt to install it.
The `--portless` flag overwrites any existing portless aliases matching `*.emulate`. Aliases are removed automatically when emulate shuts down.
For a single service behind portless:
```bash
portless github.emulate emulate start --service github
```
For a custom base URL without portless (any reverse proxy):
```bash
npx emulate start --base-url "https://{service}.myproxy.test"
# or
EMULATE_BASE_URL="https://{service}.myproxy.test" npx emulate start
```
The `PORTLESS_URL` env var is automatically set by the `portless` CLI wrapper when running a command through it (e.g. `portless github.emulate emulate start`), typically to a value like `https://{service}.emulate.localhost`. It supports `{service}` interpolation, just like `--base-url` and `EMULATE_BASE_URL`. When no explicit `baseUrl` is provided, it is used as a fallback.
Per-service overrides in the seed config (these take highest priority over all other base URL sources):
```yaml
github:
baseUrl: https://github.emulate.localhost
google:
baseUrl: https://google.emulate.localhost
```
## Pointing Your App at the Emulator
Set environment variables to override real service URLs:
```bash
VERCEL_EMULATOR_URL=http://localhost:4000
GITHUB_EMULATOR_URL=http://localhost:4001
GOOGLE_EMULATOR_URL=http://localhost:4002
SLACK_EMULATOR_URL=http://localhost:4003
APPLE_EMULATOR_URL=http://localhost:4004
MICROSOFT_EMULATOR_URL=http://localhost:4005
AWS_EMULATOR_URL=http://localhost:4007
LINEAR_EMULATOR_URL=http://localhost:4012
```
Then use these in your app to construct API and OAuth URLs. See each service's skill for SDK-specific override instructions.
## Framework Integration (Embedded Mode)
The `@emulators/adapter-next` package embeds emulators directly into a Next.js app on the same origin. See the **next** skill (`skills/next/SKILL.md`) for full setup, Auth.js configuration, persistence, and font tracing details.
The `@emulators/adapter-nuxt` package embeds emulators directly into a Nuxt app on the same origin. See the **nuxt** skill (`skills/nuxt/SKILL.md`) for the server route, Nuxt config, OAuth configuration, and persistence setup.
## Persistence
By default, all emulator state is in-memory. For persistence across process restarts and serverless cold starts, use a `PersistenceAdapter`.
### Built-in file persistence
```typescript
import { filePersistence } from '@emulators/core'
// CLI or local dev: persists to a JSON file
const adapter = filePersistence('.emulate/state.json')
```
### Custom adapters
```typescript
import type { PersistenceAdapter } from '@emulators/core'
const kvAdapter: PersistenceAdapter = {
async load() { return await kv.get('emulate-state') },
async save(data) { await kv.set('emulate-state', data) },
}
```
State is loaded on cold start and saved after every mutating request (POST, PUT, PATCH, DELETE). Saves are serialized to prevent race conditions. Generated GitHub App identities require `initialize` to atomically create the initial value or return the value another instance created first.
## Architecture
```
packages/
emulate/ # CLI entry point + programmatic API
@emulators/
core/ # HTTP server, Store, plugin interface, middleware
adapter-next/ # Next.js App Router integration
adapter-nuxt/ # Nuxt server route integration
vercel/ # Vercel API service plugin
github/ # GitHub API service plugin
google/ # Google OAuth 2.0 / OIDC plugin
slack/ # Slack Web API, OAuth, incoming webhooks plugin
linear/ # Linear GraphQL API, OAuth, webhooks plugin
twilio/ # Twilio Messaging, Verify, Voice, webhooks plugin
apple/ # Sign in with Apple / OIDC plugin
microsoft/ # Microsoft Entra ID OAuth 2.0 / OIDC plugin
aws/ # AWS S3, SQS, IAM, STS plugin
```
The core provides a generic `Store` with typed `Collection<T>` instances supporting CRUD, indexing, filtering, and pagination. Each service plugin registers routes with the shared internal app and uses the store for state.
## Custom emulators alongside built-ins
Use `npx emulate init --custom inventory` to scaffold a third-party API emulator and test. The command registers it in a discovered YAML, JSON, TypeScript, or JavaScript config, including one with existing services; unusual executable configs get printed manual registration steps. Run `npx emulate start --watch` to reload imports. Use the service URL and Inspector link in the startup banner for requests because the port depends on the config. Creating a missing local import outside the config directory also retries a failed reload. Successful reloads reset the run to seed. Existing flat seed configs still work; `--config` selects an explicit file. Node 26 loads erasable TypeScript; compile enums and parameter properties to JavaScript first. Node 24 also supports native TypeScript transforms. For authoring and testing third-party API emulators, see https://emulate.dev/docs/custom-emulators.
From vercel-labs/emulate at c77cb73, shown as plain text under its license: Apache-2.0 (permissive). The license text is in LICENSE.
View SKILL.md on GitHub at c77cb73Files
- SKILL.md19 KB · 23122529fbe5
1 file, 19 KB in total. Each file has a sha256 in the pin's manifest; the first 12 characters are shown.
Skill folder on GitHub at c77cb73More from Vercel
next-bundle-optimizer
Audits Next.js applications to identify and reduce browser bundle size and initial-load work by analyzing routes, dependencies and client outputs.
Claude Code, Codex, Cursor +4 · about 2.3K tokens · pinned 7 days ago
next-cache-components-optimizer
Optimize Next.js routes to display meaningful UI instantly on initial load or client navigation by encoding the optimization goal as a failing…
Claude Code, Codex, Cursor +4 · about 5.6K tokens · pinned 7 days ago
next-partial-prefetching-adoption
Enables Partial Prefetching in Next.js 16.3+ apps and guides adoption through auditing Link prefetch behavior, preserving UI in tests or manually, and…
Claude Code, Codex, Cursor +4 · about 6.7K tokens · pinned 7 days ago
next-partial-prefetching-optimizer
This skill optimizes Next.js client-side navigation under Partial Prefetching by defining what UI loads before and after a click.
Claude Code, Codex, Cursor +4 · about 2.8K tokens · pinned 7 days ago
apple
This skill emulates Apple's OAuth and OIDC services for local development and testing.
Claude Code, Codex, Cursor +4 · about 1.9K tokens · pinned 7 days ago
aws
This skill emulates AWS cloud services locally, providing S3 bucket and object operations, SQS message queues, IAM user and role management, and STS assume…
Claude Code, Codex, Cursor +4 · about 2.8K tokens · pinned 7 days ago
Related in Testing and QA
vitest
Vitest is a testing framework powered by Vite that provides a Jest-compatible API with native ESM, TypeScript, and JSX support.
by SanityOfficial publisher
Claude Code, Codex, Cursor +4 · about 950 tokens · pinned 7 days ago
browser-probe
This skill probes a URL with escalating headless browser configurations to detect CDN bot protection systems like Akamai and Cloudflare, then generates a…
by Adobe, Inc.Official publisher
Contains scripts
Claude Code · about 1K tokens · pinned 7 days ago
offload-onboard
This skill onboards a repository to use Offload, a parallel test runner that executes tests across Modal cloud sandboxes.
by ImbueOfficial publisher
Claude Code · about 7.1K tokens · pinned 7 days ago
e2e-testing
This skill sets up end-to-end testing for Falcon Foundry applications using Playwright and the @crowdstrike/foundry-playwright library.
by CrowdStrikeOfficial publisher
Claude Code, Codex, Cursor +3 · about 5.1K tokens · pinned 7 days ago
plugin-test-coverage
This skill guides agents through expanding Vitest unit tests and Playwright e2e tests for plugins in a monorepo.
by SanityOfficial publisher
Claude Code, Codex, Cursor +4 · about 1.2K tokens · pinned 7 days ago
test-automator
This skill guides agents in creating and maintaining automated tests across the testing pyramid, from unit tests to integration and end-to-end tests.
by zhaono1Community
Contains scripts
Claude Code, Codex, Cursor +3 · about 1.1K tokens · pinned 7 days ago
Open roles at Vercel
5 of 11 open roles on the jobs board
- Software Engineer - Data Platform
Remote (United States) (Remote)
- Software Engineer, CDN
San Francisco, California, United States; New York City, New York, United States (Hybrid)
- Software Engineer, Trust & Safety
San Francisco, California, United States; New York City, New York, United States (Hybrid)
- Solutions Architect
San Francisco, New York City, Austin, United States (Hybrid)
- Software Engineer, Compute
London, UK (Hybrid)