User photos_
Show a profile photo for any user with one Avatars call. Appwrite resolves OAuth2 identity photos, Gravatar, Libravatar, and initials, with a built-in placeholder as a fallback.
5 min read
The user photos endpoint returns the best available profile photo for a user. Appwrite tries each photo source in priority order and returns the first one that has an image, so the call always returns a picture, even for users who never uploaded one.
Use it anywhere your app shows a person: the account menu, comment threads, member lists, or a list of pending invites.
Photo sources
Appwrite checks these sources in order and stops at the first one that returns an image:
| Priority | Source | Tried when |
|---|---|---|
| 1 | OAuth2 identity photo | The user has an identity from an OAuth2 provider that exposes a photo. |
| 2 | Gravatar | An email address is known, from the user or an emailHash. |
| 3 | Libravatar | An email address is known, from the user or an emailHash. |
| 4 | Initials | A name is known, from the user or a name. |
| 5 | Placeholder | Always. A neutral person icon. |
Appwrite skips a source when it has nothing to look up with, and moves on when a remote source has no photo, times out, or returns an error. Initials and the placeholder use the same neutral gray background, so a user's avatar doesn't change color when it moves between them.
Get the signed-in user's photo
Pass current() as the userId to resolve the photo of the user who is signed in. Calling getPhoto with no userId, emailHash, or name does the same.
The web SDK returns a URL that you can use as the src of an <img> tag. The browser loads that URL on its own, so the request only carries the user's session when the browser sends the Appwrite session cookie. If your Appwrite endpoint isn't on a custom domain that shares your app's domain, pass the user's ID instead of current().
Get another user's photo
Pass any user's ID as the userId to show their photo, for example next to a comment or in a member list. Appwrite resolves the photo from everything it knows about that user: their OAuth2 identities, their email address, and their name.
The response is only the image. The user's email address and identities never leave Appwrite. If the user doesn't exist, the request fails with a 404 user_not_found error.
Get a photo from an email hash or name
To show an avatar for someone who isn't a user in your project yet, such as an invitee, pass an emailHash, a name, or both. Appwrite looks the hash up on Gravatar and Libravatar, renders the name as initials, and falls back to the placeholder.
emailHash is the SHA-256 hash of the email address, trimmed and lowercased, as a 64-character hex string. Appwrite only accepts the hash, so the address itself never appears in a URL.
Without a userId, Appwrite resolves the photo from the emailHash and name alone and leaves the signed-in user out, so their own photo never shows up for someone else.
Override a user's email or name
When you pass a userId together with an emailHash or a name, the value you pass replaces only the matching detail of that user. The rest of the user's sources stay in the chain. For example, passing a userId and a name still tries the user's OAuth2 photo and email first, and renders your name as initials instead of the user's own.
Parameters
The getPhoto method accepts the following parameters. All of them are optional.
| Parameter | Type | Description |
|---|---|---|
| userId | string | ID of the user to resolve the photo for. Pass current() for the signed-in user. |
| emailHash | string | SHA-256 hash of the trimmed, lowercase email address, as 64 hex characters. Looked up on Gravatar and Libravatar. |
| name | string | Name to render initials from. Up to 128 characters. |
| width | integer | Width of the output image in pixels, between 0-2000. Defaults to 256. |
| height | integer | Height of the output image in pixels, between 0-2000. Defaults to 256. |
| quality | integer | Output image quality, between 0-100. Defaults to 100. |
| output | string | Output format: png, jpg, or webp. Defaults to png. |
| rating | string | Maximum Gravatar and Libravatar image rating: g, pg, r, or x. Defaults to g. |
Appwrite sends every photo with Cache-Control: private, no-store, because a user's photo can change at any time. Browsers and CDNs don't cache them, so a new photo shows up the next time the image loads.
Supported OAuth2 providers
When a user signs in with OAuth2, Appwrite stores the provider's profile photo URL on their identity. The photo is updated each time the user signs in again and whenever the OAuth2 session is refreshed, so providers with expiring photo URLs stay current. If a user has several identities with photos, the most recently updated one wins.
These providers supply a profile photo:
Auth0, Autodesk, Bitbucket, Box, Dailymotion, Discord, Disqus, Dropbox, Etsy, Facebook, Figma, Gitea, GitHub, GitLab, Google, Hugging Face, Kakao, Kick, LinkedIn, Notion, PayPal, Salesforce, Slack, Spotify, TikTok, Twitch, WordPress, X, Yahoo, Yammer, Yandex, Zoho, and Zoom.
Native sign-in with Google stores the photo from the ID token's picture claim.
Other providers don't give Appwrite a photo URL. These include Apple, Amazon, Microsoft, Authentik, FusionAuth, Keycloak, Okta, and generic OpenID Connect. Users who sign in with them fall through to Gravatar, Libravatar, initials, or the placeholder.
Use cases
User photos are commonly used in:
- Account menus: Show the signed-in user's photo in the app header
- Comments and activity feeds: Show each author's photo from their user ID
- Team and member lists: Show photos for everyone on a team
- Invitations: Show a Gravatar or initials for invitees who don't have an account yet
Was this page helpful?
Share what worked or what we should fix. Once approved, our agents automatically apply suggested updates to the docs.