New:Socket for Asana Is Now Available.Learn more
Get Started

@dropthis/cli

Package Overview
Dependencies
Maintainers
1
Versions
62
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@dropthis/cli

Official CLI for Dropthis.

latest
Source
npmnpm
Version
0.41.0
Version published
Weekly downloads
248
143.14%
Maintainers
1
Weekly downloads
 
Created
Source

dropthis

@dropthis/cli

Official CLI for dropthis -- the publish layer between AI and the internet. Built for humans, AI agents, and CI/CD pipelines.

Install

npm install -g @dropthis/cli

Requires Node.js >= 20.

Quick start

dropthis login
dropthis ./index.html         # publish is the default command

Authentication

Log in with email OTP:

dropthis login

The CLI prompts for your email and a one-time code. For non-interactive environments (agents, CI), use the two-step flow:

# Step 1: Request OTP
dropthis login request --email you@example.com

# Step 2: Verify OTP
dropthis login verify --email you@example.com --otp 123456

A failed verify prints Your code has expired (otp_expired) or That code is incorrect (otp_invalid) and exits non-zero.

Scopes

Keys are minted with a capability bundle. The default for dropthis login is publish — enough to publish drops and read your own context, nothing else. To manage a team you need a wider bundle, requested with --scope on login verify:

BundleGrantsUse it for
publish (default)publish + read your own account/workspaces + mint downscoped keyspublishing, CI
teampublish + create/rename workspaces, invite/manage membersrunning a team
team-adminteam + delete workspaces, remove members, change rolesirreversible team admin
servicepublish without key-minting (workspace-pinned)automation / CI that can't mint keys
# Mint a team-scoped key
dropthis login verify --email you@example.com --otp 123456 --scope team

Minting is downscope-only — a minted key can never have more scopes than the key that minted it. Check what your current key carries:

dropthis whoami --json   # echoes the key's scopes

If a command returns insufficient_scope (exit 1, HTTP 403), your key lacks a scope that route needs. Fix it by re-logging in with the right bundle (dropthis login verify … --scope team) or, via the SDK, apiKeys.create({ scopes: ["team"] }).

Credentials resolve in this order:

  • --api-key sk_... flag
  • DROPTHIS_API_KEY environment variable
  • Stored credential from dropthis login

If you run dropthis publish without credentials in an interactive terminal, the CLI prompts you to log in inline — no separate dropthis login step needed. Disable with --no-interactive.

dropthis whoami        # Check current auth status
dropthis logout        # Remove stored credentials
dropthis logout --revoke  # Remove and revoke the key on the server

Publish

publish is the default command — you can omit it and pass files directly:

# These are equivalent:
dropthis ./report.html
dropthis publish ./report.html
# HTML file
dropthis ./report.html

# Directory (static site)
dropthis ./dist

# Stdin
echo "<h1>Hello</h1>" | dropthis publish - --content-type text/html --path index.html

# Multiple files bundled into one drop
dropthis index.html styles.css app.js

# Print only the URL (recommended for agents)
dropthis ./dist --url

# Publish by reference — the server fetches the URL, you never handle the bytes
dropthis publish --source-url https://example.com/report.html

Publish by reference (--source-url)

--source-url <url> is the explicit flag form of the positional-URL publish — same behavior as dropthis publish https://…, but discoverable and unambiguous in scripts. The server fetches the http(s) URL and serves the result; the bytes never pass through your process.

dropthis publish --source-url https://example.com/report.html
  • http(s) only — ftp://, a malformed URL, or an empty value all fail with invalid_usage ("source_url must be an http(s) URL.").
  • Cannot combine with a positional input (dropthis publish --source-url https://x ./file.html is rejected).
  • Cannot combine with --manifest — manifest files carry their own per-file source_url instead.
  • Composes with the rest of publish's flags (--title, --domain, --dry-run, etc.) exactly like the positional URL form.

Publish options

dropthis publish ./dist \
  --title "Launch page" \
  --visibility unlisted \
  --entry index.html \
  --expires-at 2026-12-31T00:00:00Z

publish always creates a NEW drop with a new URL. To change a drop you already published, use update-content or update-settings with its drop_… id — never publish again.

Canonical vs raw URLs

Every drop has a canonical url — an always-branded human view (badge guaranteed). For a single non-HTML file (.pdf, .png, .json, a URL you asked the server to fetch, etc.), publish also prints a Raw: line: the file's exact bytes at a natural path, no wrapper. Hand the canonical url to people; hand the raw URL to agents or downstream tooling that needs the real bytes.

Publishing a bundle with remote assets (--manifest)

When an AI agent generates an HTML page that references external images or other files, use --manifest to publish everything as one drop without base64-encoding the assets. The server fetches remote files during publish so bytes never pass through your process.

dropthis publish --manifest bundle.json

bundle.json shape:

{
  "files": [
    {
      "path": "index.html",
      "content": "<html>...</html>"
    },
    {
      "path": "hero.jpg",
      "source_url": "https://cdn.example.com/hero.jpg"
    },
    {
      "path": "data.json",
      "content_base64": "eyJrZXkiOiJ2YWx1ZSJ9"
    }
  ]
}

Each file entry must have a path and exactly one content key:

KeyDescription
contentUTF-8 text content (HTML, CSS, JSON, markdown, …)
source_urlPublic https:// URL — the server fetches the bytes server-side. Use this for images and other binary assets instead of base64-encoding them.
content_base64Base64-encoded bytes (for binary files you already have in memory)

Optional per-file keys: content_type (MIME type override).

The --manifest flag also works on update-content:

dropthis update-content drop_abc123 --manifest bundle-v2.json

Cannot be combined with a positional file/folder/URL argument.

All publish flags:

FlagDescription
--title <title>Drop title
--visibility <public|unlisted>Drop visibility
--password <password>Require a password to view the drop (Pro plan)
--noindexPrevent search indexing
--slug <vanity-slug>Vanity slug for a path-mode custom domain (only with --domain; Pro)
--domain <hostname>Serve the drop under one of your connected custom domains (Pro)
--sharedPublish to the shared dropthis pool, bypassing your default custom domain
--workspace <slugOrId>Target a specific workspace for this publish (delegated keys)
--entry <path>Entry file for directories
--content-type <mime>MIME type (required for stdin)
--path <path>Filename (required for stdin)
--manifest <file>Multi-file bundle JSON (see above)
--source-url <url>Publish by reference: server fetches this http(s) URL (see above). Cannot combine with a positional input or --manifest
--expires-at <datetime>Expiration datetime
--metadata <json>Metadata as JSON string
--metadata-file <path>Metadata from a JSON file
--idempotency-key <key>Idempotency key
--no-optimizeDisable server-side image optimization (byte-exact upload)
--urlPrint only the URL, nothing else
--jsonOutput full JSON response
--dry-runValidate without publishing

Oversized png/jpeg/webp images are optimized server-side by default (re-encoded smaller; paths never change), disclosed via warnings[] in the response — pass --no-optimize to opt out and upload byte-exact.

Global flags

These flags are inherited by all commands:

FlagDescription
--api-key <key>Override API key for this invocation
--api-url <url>Override API base URL
--jsonForce JSON output (implies non-interactive — never prompts)
-q, --quietSuppress status output and imply JSON
--no-interactiveDisable interactive prompts (inline auth, confirmations)
--insecure-storeStore credentials in a plaintext file instead of the OS keyring, for headless/CI boxes without a keyring backend (also DROPTHIS_INSECURE_STORE=1)

Update

Change an existing drop without creating a new URL. Content and settings are separate operations — pass the full drop_… id (not the slug):

# Replace the content at the same URL (ships a new deployment)
dropthis update-content drop_abc123 ./dist-v2

# Update from a manifest bundle (same --manifest format as publish)
dropthis update-content drop_abc123 --manifest bundle-v2.json

# Change settings only — title, visibility, password, expiry, metadata
dropthis update-settings drop_abc123 --title "New title"

# Optimistic concurrency (both accept --if-revision)
dropthis update-content drop_abc123 ./dist-v2 --if-revision 1

update-content updates the files at the URL — patch by default: files you don't include are carried forward, so you can ship a single changed file. Use --mode replace (or --replace) for a full content swap, and --delete-path <path> (repeatable) to remove a file. Like publish, update-content optimizes oversized images by default — pass --no-optimize for a byte-exact upload. update-settings changes title, visibility, password, noindex, expiry, or metadata — including --no-password to clear a password and --index to re-allow indexing. Creating a new drop is always publish — neither update command makes a new URL.

With --if-revision, a concurrent edit fails with a 409 instead of clobbering. The error shows the drop's current_revision and how to retry:

✗ Revision mismatch
  The drop changed since it was last read. Re-read it with GET /v1/drops/{drop_id} and retry with if_revision: 2 (sent as the If-Revision header).
  Current revision: 2 — retry with --if-revision 2

In JSON mode the same error carries current_revision and a next_action field.

Pull (read back)

Download what a drop is serving — by drop_… id, drop URL, or slug. URLs and slugs are resolved to your own drops; the local copy is also the rollback path (pull an old state, then update-content it back):

# By id, into ./drop_abc123/
dropthis pull drop_abc123

# By URL — resolves the slug to your drop, writes into ./abc123/
dropthis pull https://abc123.dropthis.app

# Choose the output directory
dropthis pull drop_abc123 -o ./site

Pull fetches the current deployment's file manifest and writes every file into the output directory. It is owner-side read-back via the API — it works regardless of any viewer password. Custom-domain URLs are not resolvable yet; use the drop_… id instead.

Get content (read to stdout)

Like pull, but reads to stdout instead of writing files to disk — for scripts and agents that want the manifest or a single file's exact bytes without a local directory. Accepts the same target forms: drop_… id, drop URL, or slug.

# File manifest (paths, content types, sizes) — no --path
dropthis get-content drop_abc123

# One file's exact bytes to stdout — pipeable, redirectable
dropthis get-content drop_abc123 --path index.html > index.html

# Read a historical deployment instead of the current one
dropthis get-content drop_abc123 --deployment dep_x --path index.html > old.html

Manifest mode (no --path)

Manifest mode prints JSON to stdout, but the exact shape depends on output mode:

  • Human mode (TTY) — the bare manifest, pretty-printed, nothing else on stdout:

    {
      "dropId": "drop_abc123",
      "deploymentId": "dep_xyz",
      "revision": 3,
      "status": "active",
      "sizeBytes": 4821,
      "entry": "index.html",
      "files": [
        { "path": "index.html", "contentType": "text/html", "sizeBytes": 4821 }
      ]
    }
    
  • JSON mode (piped / --json / CI / --quiet) — a single-line CLI envelope, consistent with every other command:

    {"ok":true,"content":{"dropId":"drop_abc123","deploymentId":"dep_xyz","revision":3,"status":"active","sizeBytes":4821,"entry":"index.html","files":[{"path":"index.html","contentType":"text/html","sizeBytes":4821}]}}
    

Pipes and agents always get the envelope (non-TTY stdout auto-selects JSON mode), so jq addresses .content.files:

dropthis get-content drop_abc123 --json | jq -r '.content.files[].path'

Byte mode (--path <file>)

--path <file> writes that file's exact stored bytes to stdout — no encoding round-trip, no trailing newline, nothing else on stdout. Safe to redirect straight to a file:

dropthis get-content drop_abc123 --path index.html > index.html
  • --json conflicts with --path — file bytes are written raw, so wrapping them in a JSON envelope isn't possible. Combining both is invalid_usage, exit 2.
  • TTY binary guard — at an interactive terminal, writing a non-text file's raw bytes to your screen is refused (invalid_usage: "refusing to write binary (content-type … ) to a terminal"). Pass --force to override, or just redirect/pipe (agents and pipes are never a TTY, so this never blocks a script).
  • Errors go to stderr only — an API error, a not-found path, or an auth failure leaves stdout empty, so dropthis get-content … --path x > out never writes a partial or error-shaped file.

--deployment <deploymentId>

Both modes accept --deployment <deploymentId> to read from a specific past deployment instead of the current one — the same flag as pull. Useful for inspecting or diffing an older version without rolling back.

Teams & workspaces

Publishes land in a workspace. Everyone has a personal workspace; teams add shared ones. List the workspaces you belong to and switch the active one (delegated keys):

dropthis workspace list
dropthis workspace use acme            # by slug or ws_… id

Creating and managing team workspaces needs a team-scoped key (see Scopes):

dropthis workspace create "Acme" --slug acme        # create a team workspace
dropthis workspace rename ws_team123 --name "Acme Inc"
dropthis workspace delete ws_team123 --yes          # team-admin scope

Manage who's in a workspace:

dropthis members list ws_team123
dropthis members invite ws_team123 --email teammate@acme.com --role member   # --role admin|member
dropthis members role ws_team123 acc_123 --role admin                         # --role owner|admin|member
dropthis members remove ws_team123 acc_123 --yes

Accept an invitation you received:

dropthis invitations list                          # pending invitations for your email
dropthis invitations accept --token inv_tok_abc    # accept by invite token
dropthis invitations accept-by-id inv_123          # or by invitation id

To publish into a specific workspace for one call, pass --workspace <slugOrId> on publish (delegated keys only).

Commands

dropthis [input...]                          # Publish content (default command)
dropthis publish [input...]                  # Same as above, explicit form

dropthis update-content <drop-id> [input]    # Update a drop's content (patch by default; same URL)
dropthis update-settings <drop-id>           # Change title/visibility/password/expiry/metadata
dropthis pull <id|url|slug> [-o <dir>]       # Download a drop's files to a local directory
dropthis get-content <id|url|slug>           # Read a drop's file manifest, or one file's bytes, to stdout
dropthis get <id|url|slug>                   # Show drop details
dropthis resolve <id|url|slug>               # Resolve a drop URL/slug back to its drop_… id
dropthis list                                # List your drops
dropthis list --domain reports.example.com   # Only drops on a custom domain
dropthis delete <id|url|slug>                # Delete a drop (--yes to confirm)
dropthis analytics <drop-id>                 # Show a drop's view analytics (Keep+ counts, Pro breakdowns)

dropthis deployments list <drop-id>          # List a drop's deployment history
dropthis deployments get <drop-id> <dep-id>  # Show one deployment
dropthis deployments restore <drop-id> <dep-id>  # Roll a drop back to a prior deployment (Pro+)

dropthis domains connect <host> --mode <path|dedicated>   # Connect a custom domain (Pro)
dropthis domains list                        # List custom domains
dropthis domains status <host>               # Show domain + DNS status
dropthis domains verify <host> [--wait]      # Verify DNS (exit 6 pending, 7 timeout)
dropthis domains update <host> [--default|--drop <id>]    # Repoint or set the default domain
dropthis domains remove <host> --yes         # Disconnect a domain

dropthis workspace list                      # List workspaces you belong to
dropthis workspace use <slug|id>             # Switch active workspace (delegated keys)
dropthis workspace create <name> --slug <s>  # Create a team workspace (team scope)
dropthis workspace rename <ws> --name <name> # Rename a team workspace (team scope)
dropthis workspace delete <ws> --yes         # Delete a team workspace (team-admin scope)

dropthis members list <ws>                   # List a workspace's members
dropthis members invite <ws> --email <e> --role <admin|member>   # Invite someone (team scope)
dropthis members role <ws> <account-id> --role <owner|admin|member>  # Change a member's role
dropthis members remove <ws> <account-id> --yes  # Remove a member (team-admin scope)

dropthis invitations list                    # List pending invitations for your email
dropthis invitations accept --token <token>  # Accept an invitation by token
dropthis invitations accept-by-id <inv-id>   # Accept an invitation by id

dropthis login                               # Authenticate with email OTP
dropthis login request --email <email>       # Request OTP (non-interactive)
dropthis login verify --email <email> --otp <code>   # Verify OTP
dropthis logout                              # Remove stored credentials
dropthis whoami                              # Show current auth status

dropthis account                             # Show account details, active tier + limits
dropthis account update --display-name <name>  # Update your display name
dropthis account delete --yes                # Delete your account

dropthis api-keys create [--service --workspace <ws>]  # Mint a delegated key, or a pinned CI service key
dropthis api-keys list                       # List API keys
dropthis api-keys delete <key-id> --yes      # Delete an API key

dropthis upgrade                             # Update the CLI to the latest version
dropthis doctor                              # CLI diagnostics
dropthis commands                            # Machine-readable command metadata

Agent & CI/CD usage

The CLI is designed for non-interactive use. In non-TTY environments (pipes, CI, agents), output defaults to JSON automatically.

Environment variables:

export DROPTHIS_API_KEY=sk_live_...    # API key (same as --api-key)
export DROPTHIS_API_URL=https://...    # Override API base URL (same as --api-url)
export DROPTHIS_NON_INTERACTIVE=1      # Disable interactive prompts (same as --no-interactive)
export DROPTHIS_INSECURE_STORE=1       # Plaintext credential file instead of the OS keyring (same as --insecure-store)
export DROPTHIS_NO_UPDATE_NOTIFIER=1   # Disable the startup update notice (also auto-disabled in CI, non-TTY, --json/--quiet)
export NO_COLOR=1                      # Disable ANSI color in human output (also auto-disabled when not a TTY)
dropthis publish ./dist --url

Agent protocol:

  • Use --url to get only the published URL (cleanest for agents)
  • Use --json for the full structured response
  • Use --yes for destructive commands (delete, api-keys delete, account delete)
  • Use --no-interactive to disable inline auth prompts
  • All errors write to stderr as JSON with a next_action field

Exit codes:

CodeMeaning
0Success
1API or generic error
2Invalid usage
3Auth required (no credential, or the API returned 401 — re-authenticate)
4Local input error (file or directory not found, too many files)
5Network error (could not reach the API)
6Domain verification pending (domains verify one-shot, not live yet)
7Domain verification timeout (domains verify --wait exceeded --timeout)

This table — plus the global flags (--api-key, --api-url, --json, --quiet, --no-interactive, --insecure-store) — is machine-readable from dropthis commands --json (the exit_codes and global_options fields), so an agent can discover the whole surface without scraping docs.

Some failures share exit 1 but carry a distinct error code in the JSON envelope:

Error codeHTTPMeaning & fix
insufficient_scope403The key lacks a scope this route needs. Re-login with the bundle (dropthis login verify … --scope team), or mint a key with it via the SDK. See Scopes.
quota_exceeded403/413A plan limit was hit. Check dropthis account --json (entitlements.limits vs usage) or upgrade.

JSON output shape:

{"ok":true,"drop":{"url":"https://abc123.dropthis.app/","id":"drop_abc123"}}

Error shape (stderr):

{"ok":false,"error":{"code":"auth_error","message":"No API key found.","next_action":"Set DROPTHIS_API_KEY or run dropthis login."}}

Doctor

Run diagnostics to verify CLI health:

dropthis doctor

Reports CLI version, the bundled @dropthis/node SDK version, auth source (env, flag, storage, or missing), credential storage backend (secure, insecure, or none), and — for a stored key — its capability scopes.

{"ok":true,"version":"0.38.0","sdk_version":"0.34.0","auth":{"source":"storage"},"storage":{"backend":"secure"},"scopes":["team"]}

Add --online for a network preflight an agent can run before a publish to tell apart the common failures — re-auth vs network vs an unresolved workspace:

dropthis doctor --online --json

It hits GET /v1/account (token valid? which workspace resolves? which plan?) and lists custom-domain verification status as a checks array. It exits 3 on an auth failure and 5 on a network failure, so a script can branch on the exit code.

For a pre-publish quota check, dropthis account --json returns entitlements.limits (e.g. maxStorageBytes, maxCustomHostnames, seatLimit) alongside your current usage — read it before a large publish to avoid a quota_exceeded failure.

Pricing tiers

dropthis has four tiers — Free, Keep, Pro, and Business. Free drops carry the dropthis badge and expire after 30 days; paid tiers add permanence, larger limits, custom domains, passwords, and analytics. Run dropthis account to see your active tier and its exact caps, or visit https://dropthis.app/pricing for the current plans.

Connecting a custom domain (dropthis domains connect) requires the Pro plan (1 hostname). Domains already connected keep working regardless of plan.

dropthis account shows your active tier, its limits, and the workspace your key is bound to. If the workspace kind is team, your publishes land under the team's shared custom domain automatically — no extra flags needed.

Agent skills

For AI coding agents (Cursor, Claude Code, Windsurf, etc.), install the dropthis-skills package:

npx skills add dropthis-dev/dropthis-skills

FAQs

Package last updated on 11 Jul 2026

Related posts