Skip to content

Add Presence API announcement, docs, and changelog#3010

Open
adityaoberai wants to merge 13 commits into
mainfrom
add-presence-api-docs
Open

Add Presence API announcement, docs, and changelog#3010
adityaoberai wants to merge 13 commits into
mainfrom
add-presence-api-docs

Conversation

@adityaoberai
Copy link
Copy Markdown
Contributor

What does this PR do?

(Provide a description of what this PR does.)

Test Plan

(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work.)

Related PRs and Issues

(If this PR is related to any other PR or resolves any issue or related to any issue link all related PR and issues here.)

Have you read the Contributing Guidelines on issues?

(Write your answer here.)

@appwrite
Copy link
Copy Markdown

appwrite Bot commented May 19, 2026

Appwrite Website

Project ID: 69d7efb00023389e8d27

Sites (1)
Site Status Logs Preview QR
 website
69d7f2670014e24571ca
Failed Failed View Logs Preview URL QR Code

Website (appwrite/website)

Project ID: 684969cb000a2f6c0a02

Sites (1)
Site Status Logs Preview QR
 website
68496a17000f03d62013
Queued Queued View Logs Preview URL QR Code


Tip

Git integration provides automatic deployments with optional PR comments

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 19, 2026

Greptile Summary

This PR introduces the Appwrite Presence API by adding an announcement blog post, a changelog entry, a full Realtime reference page, an auth-product guide, and an update to the channels reference table.

  • The docs/apis/realtime/presence reference is the largest new file; it documents all CRUD operations across 14 SDKs and includes subscribe examples and a channel table. It contains a claim (line 32) that presence records are automatically cleaned up when the Realtime connection closes, but no API mechanism or code is provided to tie a REST-written presence to a WebSocket session — developers who skip the heartbeat pattern based on this claim will see stale indicators.
  • The docs/products/auth/presence guide's heartbeat section calls presences.update() without expiresAt, which does not advance the expiry timestamp despite the accompanying text saying that is the goal.
  • Several subscribe examples in the Flutter, Apple, and Android SDK tabs check for bare event strings (presences.update, presences.delete) instead of the wildcard form (presences.*.update, presences.*.delete) used by the web example and the auth guide, making those handlers silently unreachable.

Confidence Score: 3/5

The reference page and auth guide contain multiple places where copying the provided snippets produces broken behavior, making this risky to publish as-is.

The 'while connected' cleanup claim describes a mechanism with no supporting API or code, the heartbeat example calls update() without expiresAt so the record never slides forward, and subscribe handlers in three SDK tabs use event strings that will never match any real event.

docs/apis/realtime/presence/+page.markdoc and docs/products/auth/presence/+page.markdoc need the most attention; the blog post and changelog are largely cosmetic.

Important Files Changed

Filename Overview
src/routes/docs/apis/realtime/presence/+page.markdoc New 1,595-line reference doc for the Presence API; contains a misleading claim about automatic presence cleanup on Realtime disconnect, and subscribe examples in non-web SDK tabs use bare event names without the required .* wildcard.
src/routes/blog/post/announcing-presence-api/+page.markdoc New announcement blog post; subscribe example correctly uses presences.*.delete wildcard form, but all upsert snippets pass ID.unique() inline, encouraging a new presence record on every heartbeat call.
src/routes/docs/products/auth/presence/+page.markdoc New auth-product presence guide; the heartbeat section explicitly aims to push expiresAt forward but calls presences.update() without an expiresAt argument, which leaves the timestamp unchanged.
src/routes/changelog/(entries)/2026-05-20.markdoc New changelog entry; references cover image as .avif while the blog post uses .png for the same path — one of the two images will 404.
src/routes/docs/apis/realtime/channels/+page.markdoc Adds presences and presences.<ID> rows to the channels table; both rows now correctly list all four event types (create, upsert, update, delete).
src/routes/docs/products/auth/+page.markdoc Adds a Presence card to the Auth product index; description and link are correct.
.gitignore Adds SKILL.md and AGENTS.md to gitignore; straightforward and correct.

Reviews (10): Last reviewed commit: "Update src/routes/docs/apis/realtime/pre..." | Re-trigger Greptile

Comment thread src/routes/blog/post/announcing-presence-api/+page.markdoc
Comment thread src/routes/changelog/(entries)/2026-05-20.markdoc
Comment thread src/routes/changelog/(entries)/2026-05-19-2.markdoc Outdated
Comment thread src/routes/changelog/(entries)/2026-05-20.markdoc
Comment thread src/routes/docs/apis/realtime/presence/+page.markdoc Outdated
Comment thread src/routes/docs/apis/realtime/presence/+page.markdoc
@adityaoberai
Copy link
Copy Markdown
Contributor Author

@ArnabChatterjee20k I'm still working on some more updates, will ping on Discord once ready

Comment thread src/routes/blog/post/announcing-presence-api/+page.markdoc Outdated
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Comment thread src/routes/docs/apis/realtime/presence/+page.markdoc
Comment thread src/routes/docs/apis/realtime/presence/+page.markdoc
Comment thread src/routes/docs/apis/realtime/presence/+page.markdoc
Comment thread src/routes/docs/apis/realtime/channels/+page.markdoc Outdated
adityaoberai and others added 2 commits May 19, 2026 22:37
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Comment thread src/routes/docs/apis/realtime/presence/+page.markdoc Outdated
adityaoberai and others added 2 commits May 19, 2026 22:47
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Comment thread src/routes/docs/apis/realtime/presence/+page.markdoc Outdated
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Comment thread src/routes/docs/apis/realtime/presence/+page.markdoc
Comment on lines +92 to +107
- **A heartbeat timer** (for example every 30 seconds) to push the `expiresAt` forward and keep the record alive while the user is active.

```client-web
async function setStatus(status, metadata = {}) {
await presences.update({
presenceId,
status,
metadata
});
}

window.addEventListener('focus', () => setStatus('online'));
window.addEventListener('blur', () => setStatus('away'));
```

There is no fixed heartbeat interval enforced by the server, so pick whichever cadence matches your UX. Anything shorter than the `expiresAt` you choose will keep the presence alive without gaps.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Heartbeat use case uses update(), which won't slide expiresAt forward

Line 92 says the heartbeat timer's goal is "to push the expiresAt forward," but setStatus calls presences.update() without passing expiresAt. The reference docs explicitly describe the heartbeat pattern as using upsert() to slide expiresAt forward. An update() call that omits expiresAt leaves the original timestamp unchanged, so presences will still expire despite an active heartbeat loop. Either replace presences.update() with presences.upsert(), or explicitly pass an updated expiresAt value.

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This gives you two ways to keep a presence alive, and you pick whichever fits your UI:

- **Heartbeat.** Upsert on focus, route change, or a periodic timer to push `expiresAt` forward. Best when presence should persist briefly across short disconnects (a quick network blip, a tab switch) or when you write presence from server code that has no live socket.
- **While connected.** If you keep a Realtime connection open, presence written over that connection is cleaned up automatically when the connection closes. Best for "online while the tab is open" UIs where you do not want to manage a heartbeat yourself.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 "While connected" cleanup is undocumented and likely incorrect

Line 32 claims "If you keep a Realtime connection open, presence written over that connection is cleaned up automatically when the connection closes." However, all presence write operations in every code example use the Presences REST service — not the WebSocket. The Appwrite Realtime SDK is a subscriber-only mechanism; there is no API shown (no connection-id parameter, no opt-in flag) for tying a REST-written presence record to a WebSocket session's lifetime. A developer who relies on this "auto-cleanup on disconnect" behavior and skips the heartbeat/TTL pattern will find their presence records surviving tab close or network drop unchanged, leaving stale "online" indicators until the default expiresAt elapses. Either the mechanism that links a presence record to a connection needs to be described with working code, or this bullet should be removed and only the heartbeat pattern documented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants