Repository navigation
Releases
Releases · dinghy-chat/dinghy
Dinghy 0.33.0
Changed
- The operator app shows a skeleton in the shape of each screen while it loads, in place of the boat and "Loading...": the sidebar and the Inbox on start, the conversation, Contacts, Analytics, Visitors and the settings pages. It fades in only after 0.3 s, so a quick load shows nothing. While the Inbox's first list loads, it no longer says "Nothing is waiting for you."
Image: ghcr.io/dinghy-chat/dinghy:0.33.0
Dinghy 0.32.0
Changed
- A visitor's reply by email from an address other than their email now names that address: Replied by email from ada@example.org. API: messages with
via: "email"havefromAddress, the address or null, in place offromOtherAddress. Replies stored before this change read as from the visitor's email.
Image: ghcr.io/dinghy-chat/dinghy:0.32.0
Dinghy 0.31.1
Fixed
- 0.31.0 has no image, because a test of the two-step removal request raced on the release's runner. This release holds the same changes as 0.31.0.
Image: ghcr.io/dinghy-chat/dinghy:0.31.1
Dinghy 0.30.1
Fixed
- 0.30.0 has no image, because the release's upgrade check still sent images to the route that 0.29.0 renamed. This release holds the same changes as 0.30.0.
Image: ghcr.io/dinghy-chat/dinghy:0.30.1
Dinghy 0.29.0
Upgrading
- Behind your own reverse proxy, accept request bodies of at least 11 MB, such as
client_max_body_size 11m;in nginx, because a file in the chat can be 10 MB. The bundled Caddy needs no change. - To turn on replies by email behind your own reverse proxy, accept 26 MB on
/v1/inbound-email, such asclient_max_body_size 26m;in an nginxlocation = /v1/inbound-emailblock, because an email can be 25 MB. A smaller limit makes the forwarder reject large emails for good. Self-hosting has the block. - Existing workspaces keep visitors' files off, so no visitor starts sending files after the upgrade. Turn them on in Settings > Appearance with Visitors can send files.
IMAGES_ORIGINis nowUPLOADS_ORIGIN; the old name still works until the next release.- If you set
UPLOADS_ORIGINand your site has a Content Security Policy, allow that origin inconnect-srcas well asimg-src, because the chat fetches a file to save it. - API: the upload routes
POST /v1/widget/{key}/imagesandPOST .../conversations/{conversationId}/imagesare now.../uploads, with no alias, because they take files as well as images. - API: in a workspace's settings,
usage.imageBytesis nowusage.uploadBytes, anddeletion.imagesis nowdeletion.uploads, as both count files too. - API: a message's
imageandimageRemovedare now oneattachment, in every answer, stream event and webhook:{ type: "image", url, width, height },{ type: "file", url, name, size },{ type, removed: true }once Dinghy Cloud deleted it after 12 months, or null.kindstays as it was.
Added
- Saved replies: the team writes common answers once in Settings > Saved replies, and anyone inserts one by typing / in the reply or note box, then changes it before sending. Every member can add, change and delete them, up to 200 per workspace. MCP has
list_saved_replies, so a bot can answer in the team's words. API:GET .../saved-replies, andPOST,PATCHandDELETEwith a session. - Files in the chat: visitors and operators send a PDF, TXT, CSV, LOG, JSON, ZIP, Word, Excel, PowerPoint, OpenDocument text or spreadsheet, MP4 or MOV file of up to 10 MB beside images. The chat shows its name and size. A file only downloads and never opens in the page. Visitors can send files in Settings > Appearance is on for new workspaces and off for existing ones, and operators can always send files. Exports carry files. On Dinghy Cloud, files count toward the 1 GB of storage and go after 12 months, as images do. Dinghy does not scan files for viruses. API: the upload routes take the file's name as
filenamein the query and answerkind: "file"withattachment: { type: "file", url, name, size }, a conversation'slastMessagehas itskind, a contact's conversations havelastKind, and the widget setting isvisitorFiles. - Mentions in notes: type @ in a note to pick a teammate. Each member a note mentions gets an alert with its text, by push and by email as their alert settings say, and the conversation is unread for them. An edit alerts only the members it newly mentions. A pick mentions the member picked, even when two members share a name. API:
mentionson a note, and on MCP'sadd_note. - Business hours: Settings > Business hours sets a time zone and up to 3 ranges a day. Outside them the widget shows the away message and "We're back Monday at 9:00 AM" on the visitor's own clock, with the date when that is more than 6 days away, even when a member is online, and asks for an email: before the first message, or after it for a visitor who has chatted. Visitors can still write. The widget gets the hours with its appearance. API:
GETandPUT .../business-hours. - The widget speaks English, French and Spanish. Language in Settings > Appearance picks one, or Visitor's language, the first of the browser's languages that the widget speaks. New workspaces start with the visitor's language, and existing ones keep English.
data-localeandDinghy.configure({ locale })win over the setting. The chat loads French or Spanish as a small file of its own, so the loader carries no translation. The team's own texts stay as written. The visitor's reply emails, transcripts and chat page follow the widget's language, with dates in that language, and the visitor panel shows it. API: the widget settinglanguage, andlocalein the widget's context report and on a conversation'svisitor. - Visitors reply by email: with
INBOUND_EMAIL_DOMAINandINBOUND_EMAIL_SECRETset, each reply email and transcript has its own reply address, and the visitor's answer goes into that conversation, reopening it if closed, as their message. Dinghy keeps the text above the quote of its email, and up to 5 attachments with the chat's checks and limits. The team sees Replied by email under it, or Replied by email from another address. Automatic answers are dropped, and an address takes 20 emails an hour and lasts 90 days after its last use. Self-hosting has a Cloudflare Email Worker for it. Off by default. API: mail reaches the newPOST /v1/inbound-emailas raw MIME, signed with the secret, and such messages havevia: "email"andfromOtherAddress. - Two-step sign-in for operators. Profile turns it on with a QR code for an authenticator app and shows 10 single-use recovery codes once. It also shows how many are left, and makes a new set with a code from the app. Each new sign-in then asks for a 6-digit code after the email link, and Settings > Team shows who has it on. A server's admin turns it off for an operator who lost their authenticator app with
chat two-factor-reset <email>. With a mail server, the account gets an email when it is turned on or off, by the operator or the admin, when a recovery code is used, and when too many wrong codes lock it. API:/v1/operator/two-factor/setup,enable,check,recovery-codesanddisable, andtwoFactorandrecoveryCodesLeftin/v1/operator/me. - Removal of two-step sign-in for an operator who lost their authenticator app and their recovery codes. Lost your authenticator app and your recovery codes? on the code screen, within 15 minutes of an email link, asks to remove it after 72 hours, only when someone else can stop the request: another owner or admin of one of the account's workspaces, or another unexpired session that passed the check. The worker emails the account a cancel link, pushes to its devices and emails the owners and admins, and tries a failed send again. The 72 hours count from that warning, and the request never completes before it. It emails the account again 24 hours before the end. Every session that passed the check shows a banner with Cancel the request at once, and Settings > Team marks Removal requested. A correct code also cancels it. A cancel signs out the sessions that never passed the check, blocks new requests for 7 days and tells the account to secure its email. With nobody to stop it, the screen points to a manual review: Dinghy Cloud's address, or the server's admin. Owners and admins can also reset a lower-ranked teammate who is in no other workspace from Settings > Team. After a removal or a reset, the next sign-in asks to turn it on again. API:
POST /v1/operator/two-factor/removal,.../removal/cancel,/v1/account/two-factor-removal/cancelwith the link's token,.../two-factor/skip-promptandPOST .../members/{operatorId}/two-factor-reset,removalCompletesAtandasksTwoFactorAgaininme, andtwoFactor: "removal_requested"andcanResetTwoFactoron members. Ateam.changedevent now also makes the operator app readmeagain. - Recovery codes have 16 letters in 4 groups, 80 random bits in place of 50. Codes made before keep working.
- Labels: put colored labels on conversations, such as billing or bugs, with L or the tag button in a conversation. Anyone on the team adds one by typing its name, up to 100 per workspace, and owners and admins rename, recolor and delete them in Settings > Labels. The Inbox filter lists the conversations with one label, rows and the conversation header show them as pills, and Analytics counts the period's conversations by label. MCP has
list_labels,label_conversationandunlabel_conversation, and itslist_conversationstakes alabel. API:GET .../labels,PUTandDELETE .../conversations/{conversationId}/labels/{labelId}, which change one label at a time, and theconversation.labeledwebhook for each change, withlabel: { id, name, color }andaction,addedorremoved. - Bulk actions in the Inbox: choose conversations with the box on each row, X, Shift for a range, or a long press on a phone, and the box beside the count chooses every row. Then close, assign, label, mark read or, for owners and admins, delete them at once. Each changes as it would alone, with its own event and webhook, and a read-only or suspended workspace can still mark them read. API:
POST .../conversations/bulkfor up to 100 conversations, with a result for each.
Security
- With two-step sign-in on, a session that has not passed the check gets 401
two_factor_requiredeverywhere butme, the check and sign-out, including the event stream at each wake, an upload's end and OAuth consent. 5 wrong codes in 15 minutes end the session, and the check answers 503check_unavailablerather than skip that limit when Valkey does not answer. The TOTP secret is encrypted with a key derived fromAUTH_SECRET, and the recovery codes are stored as keyed hashes, so after a change ofAUTH_SECRETthe check and the turn-off answer 500two_factor_unreadableuntil the admin runschat two-factor-reset. API keys are not affected. API:too_many_attempts,check_unavailableandtwo_factor_unreadableon `/v1/operator/two-factor...
Dinghy 0.28.0
Changed
- The keyboard shortcuts list is easier to scan: a close button, keys that read G then I, and the switch for single keys in its own panel. Documentation in Help shows that it opens a new tab.
- In the sidebar, the Inbox and Visitors counts sit at the right edge. With the pointer on a view, its keys take the count's place.
Fixed
- A visitor signed in with
Dinghy.identify(async () => token)now gets a country and a time zone, and shows as known in Visitors. Before, the widget sent their beat without the token, so the contact had no country.
Image: ghcr.io/dinghy-chat/dinghy:0.28.0
Dinghy 0.27.0
Added
- Keyboard shortcuts in the operator app: ? lists them, / searches, G then I, C, V, A or S opens a view, J and K move through the Inbox, R and N write a reply or a note, E closes the conversation and opens the next one, A and I assign, . opens the … menu, and P shows the visitor's panel. Esc leaves the reply box. The app shows each key where it applies, and a switch in the list turns the single keys off for this browser.
- Help in the sidebar, with the documentation and the keyboard shortcuts.
Image: ghcr.io/dinghy-chat/dinghy:0.27.0
Dinghy 0.26.0
Changed
- With a mouse, Snooze in the … menu opens its choices beside the menu on hover. On a phone it still opens them in place.
Fixed
- The reply box keeps its height when you switch between Reply and Note, as Add note is now as tall as the send button.
Image: ghcr.io/dinghy-chat/dinghy:0.26.0
Dinghy 0.25.0
Changed
- The … menu has one Snooze item, which opens its choices in place, with a row to go back. The right arrow opens it and the left arrow goes back.
- A signed detail that links to a page ending in an ID, such as
organization: https://example.com/admin/organizations/org_8f2k1, shows the ID and still opens the page. Its copy button copies the ID. - The conversation's side panel no longer shows the last page, which Pages visited already lists. A click on the visitor's email copies it.
- Reply and Note above the reply box are a small switch with an icon each, and Note turns yellow when chosen.
Fixed
- In dark mode, menus, popovers and modals stand out from the page, on a lighter card with a pale edge over a darker backdrop.
Image: ghcr.io/dinghy-chat/dinghy:0.25.0
Dinghy 0.24.0
Added
- An MCP client such as Claude Code connects with OAuth in the browser:
claude mcp add --transport http dinghy https://chat.example.com/v1/mcp, then an owner or admin approves it on one page and picks the workspace, the access (Chats or Full access) and the reply mode. The agent never sees a secret. A connected app shows in Settings > API & webhooks beside the keys, and can be disconnected there. OAuth is on whenPUBLIC_URLishttpsorlocalhost. API: OAuth discovery at/.well-known/oauth-protected-resourceand/.well-known/oauth-authorization-server,/oauth/authorize,/v1/oauth/token,/v1/oauth/registerand/v1/oauth/revoke, with Client ID Metadata Documents and Dynamic Client Registration. - MCP speaks protocol 2026-07-28, which is stateless, beside the older versions.
- Full access tools and routes, so a coding agent can install the chat: the install snippet for seven frameworks, allowed sites, an install check, identity code with no secret, the widget's look, webhook signature code, delivery replay, and test visitors. API:
/install/snippet,/install/check,/install/identity,/sites,/test-visitorsand.../deliveries/{deliveryId}/replay. - A key's reply mode: Send directly, or Drafts only, where each reply waits under the conversation as a pale suggested reply, for an operator to send, edit or discard. A draft becomes stale when the visitor writes or an operator replies after it, and the thread folds stale drafts into one card. API:
replyModeon keys, a 202{ draft }answer to a key's reply, and/draftsroutes. - Internal notes: choose Note above the reply box to write a message that only your team sees, never the visitor. API:
"note": trueonPOST .../conversations/{conversationId}/messages, a messagekindofnote, and the MCP tooladd_note. A note goes while bots are paused and while a person handles the conversation, and an operator's note neither takes the conversation from the bots nor makes drafts stale. - A bot hands a conversation to people with a reason, a summary and a last message to the visitor, and the team gets an alert. While a person handles it, a key that sends directly gets 409
human_handling, until an operator gives it back. The thread shows the handoff with the bot's note, the inbox row ends with a mark for who handles each conversation, and one dropdown picks the bot, the team or a member. API:POST .../handoff,POST .../give-back, which also clears the assignee,handlerandboton conversations,handoffon messages, and theconversation.handoffandconversation.given_backwebhooks. - Owners and admins pause every bot with one switch: replies, drafts and typing from keys answer 409
bots_paused, and the banner says who paused them and when, with Resume bots. API:PUT .../bots-paused, andbotsPaused,botsPausedByandbotsPausedAton workspaces. - A bot shows " is typing" in the chat. API:
POST .../typing, and a widgetnotice. GET /v1/eventsstreams the webhook events to an API key, for a bot with no public address, and the MCP toolwait_for_messageswaits for new visitor messages.- MCP tools for keys:
hand_off,list_members,get_contact,list_contacts,search_contacts,get_live_visitors,get_analytics, andformat: "markdown"andreplySecondsonget_conversation. - A failed webhook delivery shows the start of the receiver's answer. API:
responseExcerptandreplayOfon deliveries. - Install has a "Set up with an agent" prompt to copy, for Claude Code, Cursor or another MCP client.
- Docs: Use Dinghy with AI agents, with a block to paste into a repository's
AGENTS.md, and every doc in one file athttps://dinghy.chat/llms-full.txt. - Snooze: the … menu of a conversation snoozes it until the visitor replies, until tomorrow at 9:00 or until next Monday at 9:00. It stays open, shows Snoozed in the Inbox and does not count as waiting until then, and the visitor sees nothing. API:
{ "snooze": { "until" } }onPATCH .../conversations/{conversationId},snoozeon each conversation, aconversation.snoozedchange, and the MCP toolssnooze_conversationandunsnooze_conversation.
Changed
- A new API key or connected app starts in Drafts only. Existing keys keep sending directly, so no bot changes how it behaves.
- API keys can read the analytics, and Full access keys can read and change the widget's look.
- Settings names the two access levels Chats and Full access. The API keeps
conversationsandsetup. - Assigning a conversation in the operator app takes it from the bots, as a reply does. An API key's assign changes only the assignee.
- Settings > API & webhooks shows how many bots are connected, with a big switch to pause them, and lists connected apps, API keys and webhooks apart.
close_conversationis marked destructive, so an MCP client asks the person first.- A visitor who writes after their conversation was closed reopens it, with its assignee, instead of starting a new one. Only a visitor's first message starts a conversation, and the
conversation:startedevent andconversation.createdwebhook come only then.
Fixed
- Text you select in the widget stays readable. A site that styled its own selection made the selected text in the chat invisible, because Chrome passes the page's selection style into the widget.
- A visitor who left only their email shows it on one line at the top of the conversation's side panel, a little smaller when it is long, instead of split across two lines. Only a very long email wraps, after its @.
Image: ghcr.io/dinghy-chat/dinghy:0.24.0