---
title: "Change your profile picture"
method: POST
path: "/client/profile/image"
tags: ["Account actions"]
---

# Change your profile picture

`POST /client/profile/image`

## Request

- Base URL: `https://api.twittrapi.com`
- URL: `https://api.twittrapi.com/client/profile/image`
- Auth: API key in header `X-API-KEY`

Upload an image and set it as the profile picture of your account.

The image is uploaded like /client/media and then set as your avatar in one call. x.com crops the picture to a square in the browser before uploading; do the same if you want a specific part shown.

Limits (X): JPEG, PNG or GIF, up to 2 MB, at most 8192 x 8192 pixels. X does not animate GIFs in profile pictures.

Reference: https://www.twittrapi.com/docs/account-actions/client-profile-image

## Query parameters

- `format` 'raw' | 'simple'

## Request body

- object
  - `cookie` string, required: Cookie header of your own logged-in X session: auth_token=...; ct0=... (guest_id is used when present). How to copy it: /docs/x-session.
  - `proxy` string, required: Your proxy, format http://user:pass@host:port. The requests to X go out through it. Used only for this request.
  - `media` string, byte, required: The image file, base64-encoded. JPEG, PNG or GIF, up to 2 MB, at most 8192 x 8192 pixels (400 x 400 recommended).
  - `media_type` string: MIME type, e.g. image/jpeg or image/png. Optional: the API detects the type from the file's bytes and uses the detected type if this is missing or wrong.

## Response `200`

Wrapper built by the API: {"status_code": <X status>, "response": "<X response body as a string>"}. The HTTP status is X's status when X answered 4xx or 5xx, otherwise 200. Parse response a second time to get X's JSON. On success response is your updated user object; the new picture is in profile_image_url_https.

With format=simple: {data: User}: your profile with the new avatarUrl, the same User object as the read endpoints. When X reports an error inside the wrapper (for example a tweet that is already liked), the usual wrapper is returned unchanged.

- RawPassthrough: X's own JSON (raw format, the default), passed through unchanged. The shape is X's and can change; see https://www.twittrapi.com/docs/response-format.

## Other responses

- `400`: The body is not valid JSON. The file breaks X's limits (not JPEG, PNG or GIF; over 2 MB; over 8192 x 8192 pixels; or a damaged image header). Checked before anything is sent to X, refunded. The error names the limit and the file's value, e.g. "Banner must be between 200x100 and 8192x8192 pixels (got 120x60)" or "Profile photo must be at most 2 MB (got 3.4 MB)".
- `401`: Missing or unknown API key. Not charged.
- `402`: No balance left, or the trial expired. Not charged. Top up in the dashboard.
- `403`: Key deactivated, or the endpoint is not in your plan (trial keys and account actions). Not charged.
- `407`: The proxy is unreachable or timed out.
- `422`: cookie or proxy is missing, or the cookie has no ct0. media is missing, not valid base64, or empty. Also: the account is suspended, or X rejected the session.
- `429`: Rate limit for your key exceeded. Not charged. No Retry-After header: back off exponentially.
- `500`: Something failed on our side or between us and X. Refunded (400, 407, 408, 409 or a 5xx error are refunded). Retry with backoff.
- `default`: X refused the change: answered with X's status and {"error": "X refused the profile update: <X's reason>"}; when the image upload itself fails: "X refused the image upload: <reason>".

---

[API](https://skmtc.dev/twittrapi/apis/twittrapi-api.md) · [All operations](https://skmtc.dev/twittrapi/apis/twittrapi-api/llms.txt) · [OpenAPI document](https://skmtc.dev/twittrapi/apis/twittrapi-api/revisions/0618e38b54c2?raw)
