Documentation
Sharnix Reference
Sharnix tunnels your local dev server to a public HTTPS URL so anyone can view it — without deploying, port forwarding, or exposing your IP. You control who can access each link, for how long, and whether they can interact with it.
First setup usually takes 10 seconds to 1 minute while the agent installs/authenticates skills. After your agent is set up, future shares are usually ready in seconds.
Overview
The core flow is three objects working together:
- Agent — the
@sharnix/agentprocess running on your machine. It keeps the tunnel connection alive. - Tunnel — the persistent channel between your local port and the relay. Has a stable ID and optional permanent subdomain.
- Share link — a scoped URL you hand to a viewer. Each link has its own permission level, expiry, and access rules.
localhost:3000 → @sharnix/agent → relay.sharnix.com → https://relay.sharnix.com/p/abc123?t=TOKEN
Quick start
The normal foreground CLI flow is:
- Start your local app.
- Run the Sharnix agent.
- Copy the public URL or scan the compact QR code.
- Share it with a client, tester, teammate, or phone.
# 1. Start your app npm run dev # 2. Share a single-port app npx @sharnix/agent --port 3000 --share # 3. Multi-port apps # Add .sharnix.yaml, then run the agent from that project.
Use --port for single-port apps. Multi-port apps require a .sharnix.yaml manifest so the agent knows which local services belong to the preview.
Platform support
| macOS | Foreground CLI ready. Background service mode is not fully shipped yet. |
| Windows | Foreground CLI ready. Windows service/background mode is currently beta. |
| Linux | Foreground CLI ready. Background service mode is not fully shipped yet. |
Share links depend on your local app and the Sharnix agent being online. If either stops, visitors see a paused/offline page and can notify the owner from that page.
Tunnels
A tunnel is a stable WebSocket connection between your local machine and the Sharnix relay. The tunnel ID is derived from a SHA-256 hash of your working directory, so restarting the agent in the same project can produce the same ID and URL.
Once connected, the relay forwards all HTTP requests that arrive at your tunnel URL through the WebSocket to your local server and proxies the response back. Viewers never see your IP address.
Permanent subdomains
By default a tunnel is accessed via its ID (relay.sharnix.com/p/abc123). You can claim a permanent subdomain — my-app.preview.sharnix.com — that stays stable forever, even if the tunnel disconnects and reconnects.
# Via CLI npx @sharnix/agent --port 3000 --subdomain my-app # Via MCP claim_subdomain(tunnel_id, "my-app")
Each subdomain is globally unique across all of Sharnix. Once claimed it belongs to your org permanently.
Share links
A share link is a scoped URL that grants a specific level of access to one tunnel. You can create as many links as you want per tunnel — each with different permissions, expiry, and restrictions. Links are independent: revoking one doesn't affect others.
# URL format https://relay.sharnix.com/p/<tunnelId>?t=<JWT> # The JWT encodes: tunnelId, linkId, permission, label, expiry
Permissions
Every share link has one of three permission levels:
| read-only | Default. The relay rewrites response HTML to disable all forms, buttons, and JavaScript write operations. Visitors can browse and read but cannot interact, submit data, or trigger API calls. |
| full | Fully interactive. Visitors can submit forms, click buttons, and make API calls exactly as if they were on your local machine. Use with care — anyone with the link can write to your app. |
| blocked | Returns HTTP 403 immediately. Useful for temporarily suspending a link without revoking it. The link can be un-blocked later by updating its permission. |
Expiry & one-time view
Links can be set to expire at a specific date and time. After expiry, the relay returns a 410 Gone response. Links can also be created as one-time view — the link burns after the first successful page load and cannot be visited again.
create_share_link(tunnel_id, "read-only", expires_in_hours=48, // expires in 48 hours from now one_time_view=true // burns after first visit )
Email restrictions
You can restrict a share link to specific email addresses or entire domains without requiring viewers to log in. When a visitor tries to access a restricted link, they are prompted to enter their email address. If it matches the allowlist, they get a one-time access code via email.
| allowed_emails: ["alice@acme.com"] | Only alice@acme.com can access the link. |
| allowed_emails: ["@acme.com"] | Anyone with an @acme.com email address can access. |
| allowed_emails: ["alice@acme.com", "@partner.io"] | Alice specifically, plus anyone from partner.io. |
This feature is available on all plans. Viewers do not need a Sharnix account.
Require viewer login Pro
When require_auth is enabled, visitors must log in with their Sharnix account before seeing the preview. Unlike email restrictions, this enforces full authentication — the visitor must have (or create) a Sharnix account.
Use this when you need a strong identity guarantee, not just an email gate. You can combine require_auth with allowed_emails to allow only specific accounts.
create_share_link(tunnel_id, "read-only", require_auth=true, allowed_emails=["@acme.com"] // optional — restrict to company accounts )
IP & geo allowlists Team
IP allowlists restrict access to specific IPv4/IPv6 addresses or CIDR ranges. Geo allowlists restrict access to visitors from specific countries (ISO 3166-1 alpha-2 codes). Visitors outside the allowlist receive a 403 response immediately — no explanation is shown.
| ip_allowlist: ["203.0.113.0/24"] | Only requests from this subnet are allowed. |
| geo_allowlist: ["US", "GB", "DE"] | Only requests from the US, UK, or Germany are allowed. |
Auto-suspension
When the @sharnix/agent process disconnects (Ctrl+C, crash, machine sleeps), all active share links for its tunnels are automatically paused within seconds. Visitors see a branded "Preview paused" or offline page — not a connection error — and can notify the owner from that page.
Timeline after reconnect:
- Agent reconnects → tunnel re-established immediately
- After 30 seconds of stability → reactivation email sent to org owner (Pro/Team)
- Owner or agent calls
reactivate_link→ link goes live again
Pro and Team plans track visits that occur while the link is paused (downtimeVisits in analytics), so you can see demand even when the preview was offline.
Analytics Pro
The get_link_stats MCP tool and GET /api/v1/orgs/:slug/links/:id/stats endpoint return visit analytics for any share link.
| totalVisits | Total HTTP requests that reached the link (including repeated visits from the same person). |
| uniqueVisitors | Distinct visitors by IP address. |
| avgDurationMs | Average time between first and last request in a session, in milliseconds. |
| visitsOverTime | Array of { ts, count } buckets at hourly resolution for the requested period. |
| topCountries | Top visitor countries by request count (ISO codes). |
| topReferrers | Top HTTP Referer header values. |
| downtimeVisits | Visits that arrived while the link was paused (Pro/Team only). |
The period parameter accepts "1d", "7d", or "30d".
Custom domains Team
Map your own domain (e.g. previews.acme.com) to a tunnel so visitors see your domain instead of relay.sharnix.com. Add a CNAME record pointing to relay.sharnix.com and register the domain in Settings.
Custom domains work with all share link features — permissions, expiry, auth, and analytics apply normally. TLS is provisioned automatically via Let's Encrypt.
CLI reference
Install via npx — no global install required.
# Start a tunnel npx @sharnix/agent --port 3000 # Tunnel + immediately print a share link and compact QR code npx @sharnix/agent --port 3000 --share # First-time setup (local machine) npx @sharnix/agent setup # First-time setup (remote/headless — prints URL and exits) npx @sharnix/agent setup --print-url
| --port, -p | Local port to forward. Default: 3000. |
| --label, -l | Human label for this tunnel, shown in the dashboard. |
| --name | Agent name used on first-time provisioning. Default: local-dev. |
| --share | Create a read-only share link on connect and print the URL and compact QR code. |
| --subdomain | Claim a permanent subdomain on first connect. |
| SHARNIX_API_KEY | Your API key (shx_...). Required. |
| SHARNIX_URL | Override relay URL. Default: https://relay.sharnix.com |
MCP tools
Install the MCP server by running npx @sharnix/agent setup — it writes the config to Claude Desktop, Cursor, and Windsurf automatically. All tools accept an optional org parameter (org slug). If omitted, the first org is used.
| list_tunnels(org?) | List all tunnels with their live status, IDs, labels, and subdomains. |
| get_tunnel(tunnel_id, org?) | Get full tunnel details including all active share links. |
| create_share_link(tunnel_id, permission, ...) | Create a shareable URL. Returns the URL immediately. See share link options above for all parameters. |
| revoke_link(link_id, org?) | Permanently revoke a link. Visitors immediately see 410 Gone. Cannot be undone. |
| reactivate_link(link_id, org?) | Re-enable a link paused by agent disconnection. |
| list_suspended_links(org?) | List all links currently paused due to agent disconnect. |
| claim_subdomain(tunnel_id, subdomain, org?) | Give a tunnel a permanent URL at subdomain.preview.sharnix.com. |
| get_link_stats(link_id, period, org?) | Visit analytics. period: "1d" | "7d" | "30d". Pro plan required. |
| list_orgs() | List all workspaces the current API key has access to. |
| list_api_keys() | List all API keys on the account (prefix + label only). |
| create_api_key(label, org?) | Create a new API key. Returns the full key — show it to the user immediately. |
REST API
All endpoints require Authorization: Bearer shx_... or a session cookie. Base URL: https://relay.sharnix.com
| GET /api/v1/orgs | List orgs |
| GET /api/v1/orgs/:slug/tunnels | List tunnels |
| GET /api/v1/orgs/:slug/tunnels/:id | Get tunnel |
| DELETE /api/v1/orgs/:slug/tunnels/:id | Delete tunnel (cascades links) |
| GET /api/v1/orgs/:slug/tunnels/:id/links | List links for tunnel (masked tokens + state) |
| POST /api/v1/orgs/:slug/tunnels/:id/links | Create share link |
| POST /api/v1/orgs/:slug/tunnels/:id/links/duplicate-check | Preview duplicate policy matches |
| GET /api/v1/orgs/:slug/links | List all org links (?state= &tunnelId=) |
| GET /api/v1/orgs/:slug/links/:id | Link detail + recent visits/audit |
| POST /api/v1/orgs/:slug/links/:id/reveal-url | Copy full preview URL (audited) |
| DELETE /api/v1/orgs/:slug/links/:id | Revoke link |
| DELETE /api/v1/orgs/:slug/links/:id?permanent=1 | Remove revoked link permanently |
| POST /api/v1/orgs/:slug/links/:id/reactivate | Reactivate paused link |
| GET /api/v1/orgs/:slug/links/:id/diagnostics | Link health checks |
| GET /api/v1/orgs/:slug/links/:id/stats?period=7d | Link analytics (Pro) |
| GET /api/v1/orgs/:slug/audit?tunnel=:id | Audit events (optional tunnel filter) |
| POST /api/v1/orgs/:slug/subdomains | Claim subdomain |
| GET /api/v1/me/keys | List API keys |
| POST /api/v1/me/keys | Create API key |
| DELETE /api/v1/me/keys/:id | Revoke API key |