Avatar Upload
Upload and set a user avatar with presigned S3 URLs
Avatar endpoints require a signed-in user session. See Authentication for the initial sign-in flow.
Avatar upload is a two-step process: request a presigned upload URL, then upload the file directly
to S3. The URL is valid for 10 minutes. After upload, the image is processed to WebP. Confirm with
client.updateUser({ confirmAvatar: true }) (PATCH /users/me), or poll until avatarUrl is on
the profile.
Step 1: Get Upload URL
contentType is image/jpeg, image/png, image/gif, or image/webp.
const contentType = "image/jpeg";
const { uploadUrl, assetKey, cdnUrl } = await client.createAvatarUploadUrl(contentType);Step 2: Upload the Image
Upload the raw file bytes directly to the presigned URL. The Content-Type on the S3 PUT must be
the type you presigned.
const file = inputElement.files[0];
await fetch(uploadUrl, {
method: "PUT",
headers: { "Content-Type": contentType },
body: file,
});Step 3: Confirm
Confirming is PATCH /users/me with { "confirmAvatar": true }, which is
client.updateUser({ confirmAvatar: true }). Retry while the call returns 400 (not processed
yet) until avatarUrl is set.
async function confirmAvatar(maxAttempts = 10) {
for (let i = 0; i < maxAttempts; i++) {
try {
const profile = await client.updateUser({ confirmAvatar: true });
if (profile.avatarUrl) {
return profile.avatarUrl;
}
} catch (err: any) {
if (err.status !== 400) throw err;
}
await new Promise((r) => setTimeout(r, 1000));
}
throw new Error("Avatar processing timed out");
}Update username. The same call sets username and
removeAvatar.
If you prefer not to confirm explicitly, poll Get current user
until avatarUrl appears:
async function waitForAvatar(maxAttempts = 10) {
for (let i = 0; i < maxAttempts; i++) {
const profile = await client.getCurrentUser();
if (profile.avatarUrl) {
return profile.avatarUrl;
}
await new Promise((r) => setTimeout(r, 1000));
}
throw new Error("Avatar processing timed out");
}
const avatarUrl = await waitForAvatar();Constraints
| Constraint | Value |
|---|---|
| Max file size | 5 MB |
| Allowed types | JPEG, PNG, GIF, WebP |
| Processing time | Usually 1-3 seconds |
| CDN variants | 44px, 48px, 60px, original, raw |
Removing an Avatar
Same Update username call, with removeAvatar: true.
await client.updateUser({ removeAvatar: true });Error Handling
try {
const { uploadUrl } = await client.createAvatarUploadUrl(file.type);
const uploadRes = await fetch(uploadUrl, {
method: "PUT",
headers: { "Content-Type": file.type },
body: file,
});
if (!uploadRes.ok) {
throw new Error(`Upload failed: ${uploadRes.status}`);
}
const avatarUrl = await confirmAvatar();
console.log("Avatar ready:", avatarUrl);
} catch (err: any) {
if (err.status === 415) {
console.error("Unsupported file type");
} else {
console.error("Avatar upload failed:", err);
}
}