A public iOS example app for the compiled ConvoKit and ConvoKitUI Swift package products. The SDK implementation remains private.
The app uses a native iOS tab bar and navigation stacks for four examples:
-
Chats shows
ConversationListViewas a standard Messages-style inbox with latest-message previews, activity times and unread badges fromInboxSummaryvalues, and pushes a native conversation screen. One room is read but privately marked unread (isUnreadwith a count of 0), so the package's default row renders its numberless dot (accessible nameUnread) instead of a badge. Every sampleMessagecarries its contentrevision; one of Maya's rows was edited once (revision: 1,isEdited), so the package's default message row showsEditedbeside its time while its attachment is untouched. The pushed screen is the controlledConversationViewwith the package's default rows and composer over aShowcaseRoomfixture, which renders one WINDOW of a longer history the way a room store does (localmessages,editingMessage,replyTargetand resolved quoted previews, plusonEditMessage/onCancelEditing/onSaveEdit/onDeleteMessage/onReplyToMessage/onCancelReply/onJumpToMessage/onLoadOlder/onLoadNewer/onReturnToLatest; a save bumps that message'srevision, a delete drops it), so Maya's own rows get the default context menu and the named accessibility actions Edit message / Delete message,removeruns the package's "Delete this message?" confirmation, and the default composer switches to its edit mode (theEditing messagebanner,Cancel editing,Save message) without the backend.Every row also offers Reply, because any member may quote any row, and the composer answers with its cancellable
Replying tostrip; sending stamps the quoted id on the new row, so its quoted block renders straight away, andCanceldrops the quote without touching the draft. Maya'sm14quotes a message the window does not hold: the package draws the quoted author and text above it from the preview the fixture room resolved, and activating that block replaces the window with one around the quoted message, centres it and flashes it for about two seconds, withLoad newer messagesandJump to latestleading back. Alex'sm15quotes a message that has since been deleted, so its reference and its jump stay while the block readsOriginal message unavailable— a quoted preview is re-read, never copied, which is also why editing a quoted message updates every quote of it. -
Support demonstrates brand tinting without replacing the navigation bar or system controls, over the same
ShowcaseRoomfixture, so the tinted default rows and composer offer the same edit, delete and reply actions, edit mode and the reply strip. It also tintsConvoKitTheme.highlight, the flash behind the row a jump lands on, which followsaccentat low opacity until it is set. -
Ops demonstrates dense, host-rendered message rows inside a normal iOS conversation screen, again over a
ShowcaseRoomfixture: the custom row's context menu offers Edit message / Delete message fromMessageContext.edit/removeon Maya's own rows only, Reply fromMessageContext.replyon every eligible row,removeruns the package's "Delete this message?" confirmation, the composer switches to its edit mode and to the reply strip, and the row showsEditedfromMessageContext.isEdited. A reply renders its own one-line quote fromMessageContext.replyPreview— the resolved preview,Original message unavailable, or, while the quote is not yet resolved, the reference with no quoted text — and activatesMessageContext.jumpToReplyTarget. The fixture room resolves a quote before the row is drawn, so the quotes on screen are the first two states; the third is what the row draws for a quote a real store has asked the backend for and not yet had. Nothing is re-implemented: eligibility, the confirmation, the edit-mode composer, the reply strip and the jump flash behind the row all come from the released package. -
Live joins an authorized room through the demo backend and opens the SDK-backed inbox (
ConvoKitConversationList) with the joined room on top; previews, unread counts and the private mark-unread state come from the released package. A customrow:adds a leading swipe action, Mark unread, that callsConversationListController.markUnread(_:)on the controller handed over byonController; the controller patches the row's summary (dot on,privateStateVersionbumped), other devices catch up throughinbox_activity, and opening the room acknowledges with the version captured at open, which clears the marker. The room itself is the package'sConvoKitConversationwith its default rows and composer, so your own confirmed messages get the context menu and the named accessibility actions Edit message / Delete message, saves send the snapshot revision (aREVISION_CONFLICTreloads the row and keeps your draft), deletions tombstone the row on every device, and edited rows showEdited. Replying, quoted blocks, jump-to-message and the way back to the latest are wired by the same wrapper: it batches the quoted previews for a page, keeps a quote pointing at a deleted message asOriginal message unavailable, and holds new messages back while the window is jumped until you return to the latest. The author endpoints need the 0.8 backend and the reply routes need the 0.9 backend, both of which the hosted ConvoKit API the example talks to already serves; against an older backend a save or delete fails with a 404 that keeps the row and edit mode, and the reply preview and jump affordances retire instead of failing repeatedly.
Open ConvoKitSwiftExample.xcodeproj in Xcode and run the ConvoKitSwiftExample scheme on an iOS 15+ simulator.
ConvoKitExample/Tests covers the showcase's own room state — the window, the reply target, the quoted previews and the jump — and runs from the same scheme (Product > Test, or xcodebuild test -scheme ConvoKitSwiftExample -destination "id=<simulator udid>").
The live example sends the public client ID to https://convokit-open-chatroom.vercel.app. The client secret is not present in this repository or the app binary; the backend owns token issuance and room membership policy.


