MCP HeartbeatTHE MCP OBSERVATORY
Public workspace

Explore

Evidence for your next connection.

Independent measurements of remote MCP servers. Every observation has a timestamp.

Read-only probes

MCP server · Code & DevOps

dotsy

Build and publish static sites on dotsy with draft-first MCP tools, OAuth Connect, and API keys.

Checks passed
12 / 22

2 failed · 8 not measured

Median response
137 ms

Median of successful probes over 7 days

30-day uptime
Not measured

Share of countable probes over 30 days, including daily rollups. Auth challenges are excluded.

Discovered tools
120

Tool definitions returned by this server

Independent monitoring

Health & checks

Status history

Outdated check

Last connection measurement is over 24 hours old. Current availability is unknown.

Last checked
Check summary by test group
Test areaPassedFailedUnmeasured
ConnectionCan a client connect and discover tools?
500
Reliability & speedDoes it respond consistently and quickly?
004
Access & authenticationWhat is required to use this server?
102
Tool qualityAre the tool definitions usable by an agent?
310
Publisher identityCan the publisher be traced to its source?
312

Unmeasured means there is not enough evidence to decide. How these checks work

Inspect individual checks 22 recorded

Core

  • Pass
    Reachable

    Latest probe returned HTTP 200 in 137 ms.

  • Pass
    Valid handshake

    protocolVersion 2025-11-25, serverInfo.name dotsy.

  • Pass
    Lists tools

    tools/list returned 120 tools.

  • Pass
    Current protocol

    Negotiated 2025-11-25. The bar is 2025-06-18 or newer.

  • Pass
    HTTPS

    The endpoint URL is https.

Performance

  • Not measured
    Fast (p50)

    Median latency 137 ms over 1 samples in 7 days. The bar is 1000 ms. Need at least 5 samples.

  • Not measured
    Consistent (p95)

    95th percentile 137 ms over 1 samples in 7 days. The bar is 3000 ms. Need at least 20 samples.

  • Not measured
    Reliable (uptime)

    1 of 1 attempts returned a tool list in 30 days (100%). The bar is 99%. Need at least 30 samples.

  • Not measured
    Stable tool list

    Fewer than two successful probes in 30 days, so tool-list stability is not measured.

Access

  • Pass
    Open access

    tools/list succeeded with no credential, and the record declares none.

  • Not measured
    Standard auth

    Auth is not required, so the OAuth metadata check does not apply.

  • Not measured
    Free tier cited

    No publisher quote has been checked.

Tools

  • Pass
    Tools described

    Every tool description is at least 20 characters.

  • Pass
    Valid input schemas

    Every inputSchema is a JSON Schema object.

  • Fail
    Parameters documented

    474 of 648 parameters have a description (73%). The bar is 80%.

  • Pass
    Safety hints

    Every tool sets readOnlyHint or destructiveHint.

Publisher

  • Pass
    Verified namespace

    Listed in the Official MCP Registry.

  • Pass
    Website matches publisher

    The website host matches the reverse-domain namespace.

  • Fail
    Source repo linked

    No repository URL is on file.

  • Not measured
    Repo owner matches

    This namespace is not an io.github login, so the owner comparison does not apply.

  • Pass
    Recently updated

    Updated 2026-11-11T04:32:00.502801Z, within 180 days.

  • Not measured
    Open-source licence

    No GitHub repository to ask about a licence.

Start using dotsy

Connect to this server

Choose your client, copy the configuration, then enable the server in your client’s MCP settings.

Run this command in your terminal, then restart Claude Code.

Claude Code

claude mcp add --transport http dotsy https://mcp.dotsy.ai/mcp

Capabilities

Tools 120

Showing 100 of 120 tools.

adapt_site_analyze

Propose nav wiring + blog collectionization for an imported mirror (draft, opt-in). Read-only; returns per-adapter reports + proposalEtag. Nav decline may include nextStep (e.g. mega-menu → edit fragments/header.html). Wait for mirror-vs-editable answer if requiredDecision pending.

Discovered
adapt_site_apply

Apply the adapt proposal (draft): wire nav into the menu store and/or rewrite the blog index to a live <dotsy-collection>. One undo covers the whole apply; a second apply is refused until adapt_site_revert (or force). Queued applies are polled to completion.

Discovered
adapt_site_revert

Atomically restore everything the last adapt_site_apply wrote (fragments, the menu doc when the op touched it, index, member configs, routes).

Discovered
add_custom_domain

Connect apex and/or www on a paid plan; starts a DNS connect session.

Discovered
add_idea

Add an idea from outside the site (draft board item or inbox suggestion). Idempotent on externalRef.

Discovered
apply_changeset

Stage writes[] + deletes[] in one call; attach routes via writes[].route. writes[].ifMatch (hash from get_site_manifest; "" = must not exist) guards each key (a delete takes { key, ifMatch } too); atomic:true makes one stale key write nothing (409 changeset_conflict). At most 10 writes; each body ≤60KB and the call ≤80KB. Larger new pages: stage_content_chunk then writes[].bodyStaging, or dotsy push / PUT content-raw.

Discovered
batch_patch_content

patch_content on multiple keys; all-or-nothing validation. Preferred edit path for pages over 60KB. replace-string value/replace ≤60KB; whole call ≤80KB.

Discovered
bulk_put_assets

Upload 1–200 CMS assets; key = path after /assets/, or sitePath for an exact URL path (e.g. /.well-known/security.txt, /ads.txt). Each item: exactly one of bodyBase64, bodyText (plain text for .css/.js/.mjs/.json/.svg/.txt/.xml only — not .html pages), or importFromUrl. Optional bodySha256 checks the sent bytes; response sha256 = stored bytes (WebP may differ). JPEG/PNG/static GIF are re-encoded to WebP (response key photo.webp; /assets/photo.jpg keeps serving it) — use the response key in CSS/JS; optimize:false stores the bytes as sent at your key; animated GIFs are always kept. Live in the editor and draft preview at once; on the published site after the next publish.

Discovered
bulk_put_content

Stage many content keys (pages, layouts, fragments). Content only — not routes or assets. Each body ≤60KB and the whole call ≤80KB; larger pages use stage_content_chunk, dotsy push, or PUT content-raw. May queue above the inline threshold.

Discovered
claim_site

Move the guest draft onto your signed-in dotsy account. Requires OAuth Connect; pass the guestToken from start_site.

Discovered
create_site

Create empty site; seeds brief. Globally taken slugs auto-suffix to `{slug}-{adjective}-{noun}` (default); pass onSlugTaken:"fail" to get a 409 instead of a renamed site.

Discovered
delete_asset

Delete a static asset by key. The editor and draft preview drop it at once; the published site drops it at the next publish.

Discovered
delete_content

Delete content key (tombstone if published). A fragments/* section that pages still place is refused with section_in_use (lists the pages) — detach it or remove it first.

Discovered
delete_draft_test

Remove a draft A/B test (releases variant bodies; does not publish).

Discovered
delete_menu_item

Remove one item from a menu (page stays live).

Discovered
delete_route

Remove a route by path.

Discovered
delete_site

Permanently delete site; confirmSlug must equal slug.

Discovered
detach_section

Give one page its own copy of a shared section; every other page keeps the shared one. A draft — publish_site to go live. A section the layout places is hidden on that page instead (share_section name + hide).

Discovered
discard_drafts

Discard unpublished drafts: all (omit key/keys/routes/menus), one content key (key), menu draft only (menus:true), or a selection (keys, routes). Destructive — check get_draft_status first.

Discovered
edit_page

Open the interactive page canvas to change content: the user clicks an element, then you call patch_content. Use when the intent is editing — not for verify-only checks (use preview_page).

Discovered
estimate_test

Estimate days to reach promote readiness for a page (traffic baseline). Read-only.

Discovered
find_replace

Case-insensitive find→replace across pages in one staged commit. Batch all replacements into ONE call — never parallelize find_replace on the same key (concurrent edits surface as per-key conflict). find/replace ≤60KB.

Discovered
form_recipients

Who a site's forms may email. A form's `to` address gets submissions only when it is a verified site member or it confirmed by a one-click link we email it (no account, no sign-in, no site access). action: `list` (confirmed + waiting addresses), `status` (one address: member | confirmed | pending | expired | unconfirmed), `request` (email the confirm link; 7 days, single use; max 3 per address, 20 per site and 50 per account a day), `revoke` (stop form emails to a confirmed address). A publish already sends the link once by itself when a form emails an unconfirmed address. Never ask the user for the link — it goes to that inbox only.

Discovered
get_account_context

Account, user, memberships[]. Pass workspace on writes when memberships.length > 1.

Discovered
get_activity

List site activity or fetch one change diff (pass id). Filters: who, state, actor (me), since, limit≤20. Notes from context are visible to everyone on the site — no secrets.

Discovered
get_adapt_status

Read adapt state: proposal summary + proposalEtag (+ applied/consumed flag), undo-record presence, active or queued job progress. Use to resume in a fresh session.

Discovered
get_analytics

Read-only traffic overview (default) or full breakdowns via include[]; optional bot id for crawler page drill-down.

Discovered
get_asset

Read one asset (metadata + base64 + stored sha256). sha256 is the stored blob; may differ from upload bodySha256 when IMAGES re-encodes rasters. Live in the editor and draft preview at once; on the published site after the next publish.

Discovered
get_board

List board items with status, stamp fields, and baked vote counts (draft overlay included). Live vote totals: site host GET /__dotsy/votes.

Discovered
get_collection_schema

Read the site's collection field definitions (`_data/collections.json`, draft view): { schema: { v: 1, collections: { "<key>": { fields[], settings? } } }, hash }. hash is null when no schema exists yet — pass it as put_collection_schema ifMatch. 409 collection_schema_invalid { hash, issues } means the stored file is broken: fix it with put_collection_schema using that hash.

Discovered
get_content

Read one content key; optional selector (region) or published=true (live body). Bodies over 40KB without a selector return a truncated summary — use selector, batch_patch_content, or dotsy pull.

Discovered
get_custom_code

Read the site-wide custom code: `draft` (what the next publish puts live) and `published` (what visitors get now) for both boxes — head (before </head>) and body (before </body>) — plus `pending`, `runOn` and `maxChars`.

Discovered
get_custom_domain_connect

Current connect session and nextAction (browser URL or manual DNS guide).

Discovered
get_draft_status

Pending draft changes: content keys and routes with status. May include requiredDecision (publish_confirm) before publish_site.

Discovered
get_form_submission

Read one form submission with the full field payload (explicit PII access — use only when needed).

Discovered
get_menu

Read a menu's draft items and etag; menu rules → get_skill('nav').

Discovered
get_menu_doc

Read the whole menu doc (all menus + shell/template), etag for put_menu_doc, and issues (by item id) — page_not_routable, page_missing, page_dead_link, page_is_redirect — computed from the draft routes, so a link that won't show or leads nowhere shows up before publish.

Discovered
get_plan

Read-only workspace plan and pooled usage; pass slug for this site's add-ons. Call before a large build.

Discovered
get_report

Your dotsy bug reports. Omit id for the list; pass id for one ticket and its public replies.

Discovered
get_route

Get one route by path (home is '/').

Discovered
get_site

Site detail, stats, publicUrl, brief head (default-on), and readiness flags. pages[] is a ~25-entry head by default (stats.pages has the true count) — pass pages: true for the full array (capped at 1000), or enumerate everything with list_content/get_site_manifest. Large sites (200+ pages): list_pages is paginated — use cursor or get_site_manifest for the full route set.

Discovered
get_site_build_progress

Read-only build progress view (structure/adapt jobs or after import). structuredContent.forHumans holds the headline and progress. import_site_from_url blocks until done, so this is not needed during an import; get_site has the full state.

Discovered
get_site_manifest

Content keys + hashes only (optional routes=true) — static files live in list_assets, not manifest. Diff keys+hashes before apply_changeset; stage only changed bodies.

Discovered
get_site_outline

Site shape: every layout and shared section (`sections`: fragments/* by name, with page count, whether the file exists and staged-change flag), whether a layout is missing, redirects count, menus grouped by where they show, and collections with their page placements. Use for 'is my layout missing', 'which shared sections exist and where', 'where does this menu show' — without listing every page. Read-only; indexing mirrors list_pages (a freshly imported/graduated site may still be indexing).

Discovered
get_site_tasks

What needs fixing on a site, from stored checks. Call after writes, before publish_site.

Discovered
get_skill

Skill body + optional questions[]. Accepts an id OR a synonym (e.g. 'list', 'menu') — resolves aliases and suggests near-misses. Start with intake when ambiguous.

Discovered
get_structure_result

Last structure apply job result (structuredKeys, conflicts, partial).

Discovered
get_structure_status

Flat vs structured page counts; chromeCoverage = real per-fragment page counts + missedPages (check before promising sitewide edits). Informs user — do not auto-run analyze/apply while requiredDecision pending.

Discovered
graduate_site

Enable site search & collections (kv → do-sqlite), one-way. Unlocks search_content, collection indexes, visitor /__paige/search, and moves any R2 form-submission ledger into SiteDb. 409 blocked: `reason` names the gate — unsupported source backend (never overridable); strictDrafts (default true; strictDrafts:false skips it) on unpublished drafts or unrecovered KV rows; or an incomplete-looking KV snapshot (e.g. a page deleted minutes ago), the only gate force:true overrides. `audit` (+ `audit.warnings`) is aggregate counts only, no row keys: judge the gap before forcing. Anything outside the frozen snapshot is unreachable once it lands.

Discovered
import_site_from_url

Import URL to draft. On complete, response may include requiredDecision — preview then ask mirror vs editable before structure_*.

Discovered
infer_collection_schema

Suggest fields for one collection from a sample of its items' meta.custom values (published data, else drafts) — writes nothing. Returns { sampled, suggestions: [{ field: { key, type, options? }, count, samples, defined }], skipped }. Review, then add the ones you want via put_collection_schema.

Discovered
inspect_collection

Collection state — count, server.mode, sample entries, tag (membershipKind, match=) when discovered; plus name, noun, URL pattern, layout, where it's listed, and post fields used. Pass status/q/cursor/limit (any one, even empty) for a full items[] page instead: status draft = never published; a published post with unpublished edits is status published with hasChanges:true (never draft) and shows its staged title/date/tags/author; scheduled = future visibleAt. Never-published drafts come from staged content (no extra reads, no publish needed to see them); published/scheduled come from the index. limit defaults to 50, clamped 1-200. Omit all four for just the base inspect (no items[]).

Discovered
install_product_kit

Add a roadmap, changelog and/or help centre to a site as drafts (never overwrites; rerun finishes a partial install).

Discovered
list_assets

CMS uploads under assets/ only — not mirrored clone CDN (get_site mirroredAssets or import warmJob). Not content — use list_content. Live in the editor and draft preview at once; on the published site after the next publish.

Discovered
list_collections

Collections on the site — name, noun, item count (or 'not published yet'), URL pattern, and whether any member is staged. Includes a collection only a draft page lists. Returns a bare array (not wrapped in an object) — pass each row's key verbatim to inspect_collection/update_collection.

Discovered
list_content

List content keys (HTML/md); not assets — use list_assets. Defaults to 50 keys per page — raise limit (max 1000) or pass cursor (from nextCursor) to page through the rest. Per-row `size`/`missing` are measured automatically only on pages of ≤100 rows; past that they're ABSENT (not measured, never `null`) unless you pass withSize:true, which forces measurement at a cost of one storage read per returned row. Only `size: null` + `missing: true` means the page's stored bytes are gone.

Discovered
list_custom_domains

List all custom hostnames and connection status for the site. A connected bare domain with redirectorState "attention" is NOT redirecting (see `attention`).

Discovered
list_form_submissions

List form submissions (metadata + bounded field preview — not full PII). Works on kv and do-sqlite backends.

Discovered
list_goals

List site conversion goals (pageview paths and form submits). Required before start_test.

Discovered
list_ideas

Search draft/published board items and open suggestions by title token overlap.

Discovered
list_my_sites

List your dotsy sites. Renders a site-picker for humans; agent reads structuredContent. Use to choose a site — not for editing content (use edit_page) or verify-only checks (use preview_page). Defaults to your active workspace; pass workspace (org id or slug from get_account_context memberships) to list another workspace's sites without switching the dashboard session.

Discovered
list_notifications

Account notification inbox (Needs you · Updates). Summary-first: tab counts plus compact rows with nextAction (MCP tool or dashboard URL). OAuth person only — not API keys.

Discovered
list_pages

List pages on a site — route settings (path/title/navLabel/purpose) by default, one row per route. Renders a page-picker for humans (redirect and worker routes left out there — nothing to open in edit_page); agent reads structuredContent. Use after picking a site — not for editing (use edit_page) or verify-only checks (use preview_page). Pass view:'pages' to group by layout instead — adds layout/noLayout/q filters, what each page places, and indexing progress; use that for 'what pages use this layout' or 'is this page indexed yet', not for route settings. Paginated — pass cursor (from nextCursor) for more; partial:true means this page is a window, not the full route set.

Discovered
list_skills

Paige build skills (id + whenToUse). Pull get_skill on demand — do not duplicate in tool text.

Discovered
list_suggestions

List form suggestions awaiting moderation (duplicate hints against the board).

Discovered
list_versions

List the site's published versions, newest first (who, when, pages, live, restorable). Use before restore_version.

Discovered
list_votes

List voters on one board item (voter id + source only — no email).

Discovered
mark_notifications_read

Mark Update notifications read (ids or all). Needs-you Actions refuse with 422 action_not_markable — fix the cause (it clears itself); only the person can dismiss them in the dashboard.

Discovered
moderate_suggestion

Decide one form suggestion from list_suggestions: approve (new draft board item; stages content, does not publish), merge (into an existing board item, subscribes the voter/email) or decline (no board item).

Discovered
new_post_template

Read-only scaffold for a new post — suggested key/path, membership meta, blank or duplicate body. Then put_post (+ optional put_route).

Discovered
optimize_assets

Shrink heavy images in place (0.98): JPEG/PNG/still GIF → WebP at the same address, so no HTML changes. keys = site paths from verify_page health.assets[].ref — /assets/… uploads or clone paths like /wp-content/… (1–50 per call; batch keys from several entries). Skips animated images, already-small files and non-images (`skipped`); idempotent. The replaced file is kept under .originals (never served). Spends the daily image budget like an upload — dryRun:true reports the saving without spending it. The draft serves the smaller file at once. Your live site shows the smaller file after you publish (some imported files sooner).

Discovered
patch_content

Edit one content key via ops[] (selector ops or replace-string; wrap/unwrap/move restructure siblings). Stages draft; op shapes in schema.

Discovered
patch_route

Partial route update (only sent fields change; an OMITTED field is left alone). On a field that accepts null (contentKey, redirectTo, redirectStatus, preserveQuery), sending null CLEARS it back to its default — different from omitting it. To set redirectTo/redirectStatus, include purpose: "redirect" in the SAME call — the check looks only at what's sent, not the route's stored purpose, so a PATCH that sets redirectTo without repeating purpose: "redirect" (even on a route that's already a redirect) 400s invalid_body.

Discovered
preflight_site

Plan check before publish or large build (counts, plan page cap, seo suggestions; imports: form_unwired advisory, webflow_store blocking). When ok is false, blocking lists the failed suggestion codes. Read-only.

Discovered
preview_page

Verify-only composed HTML check; home preview may include requiredDecision — ask mirror vs editable before structure_*.

Discovered
promote_experiment

Promote a winning A/B variant to live — explicit user instruction only; see get_skill('verify') § A/B.

Discovered
publish_site

Publish draft to live. handoff required; feedback optional. Warnings (form_unwired, store, SEO) are advisory — tell the user. Site-check errors return a publish_issues decision: tell the user; to publish anyway, call again with publishWithIssues = its code.

Discovered
put_collection_schema

Replace the whole field schema (draft; publish makes it live). Edit what get_collection_schema returns. Collection keys exactly as list_collections returns them ("blog/" or an id). Field: { key, type, label?, help?, required?, unique?, inCard?, default? } — type text (multiline, minLength, maxLength) | number (min, max, integer) | boolean | option (options[] required) | multiOption (options[] required, max) | link | email | phone | color. Keys: letter then letters/digits/_ (≤40), not a built-in post field (author only as text), not secret-looking. ≤60 fields per collection. settings.defaultSort: date:desc|date:asc|title:asc|slug:asc. Removing a collection's entry drops its definitions (values stay on the posts). Values go in put_post meta.custom (fieldWarnings are soft). 400 invalid_collection_schema lists issues; 409 conflict = stale ifMatch.

Discovered
put_content

Stage one content key. Body ≤60KB. Larger pages: stage_content_chunk + apply_changeset bodyStaging, dotsy push, or PUT content-raw. Edits to an existing large page: batch_patch_content.

Discovered
put_goals

Create or replace all site conversion goals (≤50). Required before start_test when no goal exists.

Discovered
put_menu_doc

Replace the whole menu doc (ifMatch from get_menu_doc required). Each item may omit menu — the enclosing menu key in doc is used.

Discovered
put_menu_item

Partial upsert one menu item: send only the fields to change; every omitted field (parent, sort, label, kind, ref, newTab, html/childTemplate/childShell/attrs/data) keeps its stored value, and parent: null moves it to the top level. A new id needs label, kind and ref (parent defaults to null, sort to the end). To remove rich keys, use put_menu_doc. A brand-new id dedupes by (menu, ref) — reuses an existing item linking the same target instead of creating a duplicate. An id that already names an item always updates that exact item, even if another item links the same page.

Discovered
put_post

Stage a blog post via structured meta+body (?format=post). Key e.g. blog/my-post.html. Declared membership: meta.collections; schedule: meta.visibleAt; SEO title override: meta.seoTitle (card always shows meta.title); custom fields: meta.custom (typed per collection by get_collection_schema; the response's fieldWarnings flag values that don't fit — soft, never blocking).

Discovered
put_route

Create/replace route; contentKey derived from path if omitted. On a field that accepts null (contentKey, redirectTo, redirectStatus, preserveQuery), sending null clears it back to its default.

Discovered
reapply_custom_domain_oauth

Re-apply DNS with stored Cloudflare OAuth grant (no browser).

Discovered
refresh_custom_domain

Poll one hostname until DNS/cert propagates.

Discovered
reindex_collection

Build/finish collection indexes after publish returns collectionDataPending or collectionSqlPending.

Discovered
remove_custom_domain

Remove one custom hostname from the site.

Discovered
remove_votes

Remove one voter's vote and drop their release subscription for that item.

Discovered
rename_content

Re-key a page by slug (draft or published static), server-side hash copy. Default deletes static routes; movePath:true repoints the route, rewrites menu refs, redirects and root-relative / {slug}.dotsy.site hrefs in draft HTML (as rename_page), and for an already-published page leaves a 301 (leaveRedirect, default true). Retry-safe: 409 rename_failed rolls back, resend. On fragments/<name>.html it also rewrites every <dotsy-fragment name> reference and hide marker in one commit. Then publish_site.

Discovered
rename_page

Change a page's URL: moves its route from `from` to `to`. Menu links and redirects to the old path retarget automatically; a 301 stays at the old path by default (leaveRedirect). Root-relative and https://{slug}.dotsy.site/ hrefs in draft page, layout and fragment HTML are rewritten (always linksRewritten; not custom-domain absolutes or code samples; linksRewriteTruncated when scan caps at 100 HTML keys (500 on sites with full content search); publish to ship). Retry-safe (resend after any error). Errors (each with a hint): 404 route_not_found; 400 reserved_route, invalid_body; 422 rename_same_path, rename_pattern_route (:param routes), rename_redirect_route (edit its redirectTo); 409 rename_experiment_running (end the A/B test), rename_target_exists (200 when to already serves from's content). Then publish_site.

Discovered
rename_site

Rename the site slug (hostname {slug}.dotsy.site). Owner-only; use the returned slug afterwards. Published site: the old slug redirects on the API (301 reads, 308 writes) and the old host 301s, both reserved until delete or rename-back. Never published: the old slug 404s and its hostname is released (create_site can reuse it). Stored HTML URLs are not rewritten (use find_replace).

Discovered
reorder_menu

Set final menu order. Pass ifMatch from get_menu; stale → 409 with current items.

Discovered
reply_to_report

Add information or answer dotsy's question on your own report.

Discovered
report_bug

Report a dotsy bug, or ask a support question (kind question — AI answer from the help centre). Bugs attach recent errors and return a ticket id.

Discovered
restore_version

Bring an earlier published version back as unpublished changes (page content only — routes, menus, images and settings stay). version: a number from list_versions, or "previous". dryRun: show what would change. Then review and publish_site, or discard_drafts to undo; publish:true makes it live at once.

Discovered
revert_change

Undo one activity event by staging the prior version as draft only — call publish_site to go live. Respects AI access.

Discovered
review_changes

Review queue: what changed and isn't live yet. list (counts first) → get one item (hidden changes, optional diff, bodyChanged: false means only title/meta/route fields changed — review hidden, not the visible page) → mark_ready / unmark (≤50 ids). Then publish_site onlyReady:true. Drafts-only sites: a person marks.

Discovered
search_content

Find pages containing a phrase (grep without reading bodies). Requires do-sqlite — graduate_site first if search_unavailable.

Discovered
set_analytics_provider

Connect a third-party analytics provider (GA4, Plausible, Fathom, Umami) or remove it (provider 'none'). dotsy adds the provider's script to the <head> of every live page — live immediately, no publish needed. Replaces any earlier provider (one per site). Use this instead of pasting a GA4 gtag snippet into a layout. Other tags (Google Tag Manager, ads pixels, Clarity, search-console verification <meta>) go in set_custom_code.

Discovered

Recent measurements

Probe history

View status
Latest stored probes. Raw probe rows are kept for 14 days.
CheckedResultResponseTools
Connected137 ms120