> ## Documentation Index
> Fetch the complete documentation index at: https://auth0.com/llms.txt
> Use this file to discover all available pages before exploring further.

> Learn how to use user metadata to change a user's picture field and how to change the default picture for all users.

# Change User Pictures

export const AuthCodeGroup = ({children, dropdown}) => {
  const [processedChildren, setProcessedChildren] = useState(children);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      unsubscribe = window.autorun(() => {
        const processChildren = node => {
          if (typeof node === "string") {
            let processedNode = node;
            for (const [key, value] of window.rootStore.variableStore.values.entries()) {
              const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
              processedNode = processedNode.replaceAll(new RegExp(escapedKey, "g"), value);
            }
            return processedNode;
          } else if (Array.isArray(node)) {
            return node.map(processChildren);
          } else if (node && node.props && node.props.children) {
            return {
              ...node,
              props: {
                ...node.props,
                children: processChildren(node.props.children)
              }
            };
          }
          return node;
        };
        setProcessedChildren(processChildren(children));
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  return <CodeGroup dropdown={dropdown}>{processedChildren}</CodeGroup>;
};

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****MASKED*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

Auth0 normalizes common profile properties in the User Profile, this includes the `name`, `picture` field and more. The picture field is populated by either the social provider profile picture or the Gravatar image associated with the user's email address.

By default, all database users will have a placeholder image with their initials. When you authenticate the user, this picture field is referred to as `user.picture`.

## Use the Management API

The `user.picture` attribute is not directly editable when provided by <Tooltip tip="Identity Provider (IdP): Service that stores and manages digital identities." cta="View Glossary" href="/docs/glossary?term=identity+providers">identity providers</Tooltip> other than Auth0 such as Google, Facebook, or X. To edit this attribute, you must configure your connection sync with Auth0 so that user attributes will be updated from the identity provider only on user profile creation. To learn more, read [Configure Identity Provider Connection for User Profile Updates](/docs/manage-users/user-accounts/user-profiles/configure-connection-sync-with-auth0). Root attributes will then be available to be edited individually or by bulk import using the <Tooltip tip="Management API: A product to allow customers to perform administrative tasks." cta="View Glossary" href="/docs/glossary?term=Management+API">Management API</Tooltip>. To learn more, read [Bulk User Imports](/docs/manage-users/user-migration/bulk-user-imports).

Alternatively, you can use metadata to store the picture attribute for users. For example, if your app provides a way to upload profile pictures, once the picture is uploaded, you can set the URL to the picture in the `user.user_metadata.picture`:

<AuthCodeGroup>
  ```bash cURL theme={null}
  curl --request PATCH \
    --url 'https://{yourDomain}/api/v2/users/USER_ID' \
    --header 'authorization: Bearer MGMT_API_ACCESS_TOKEN' \
    --header 'content-type: application/json' \
    --data '{"user_metadata": {"picture": "https://example.com/some-image.png"}}'
  ```

  ```csharp C# theme={null}
  var client = new RestClient("https://{yourDomain}/api/v2/users/USER_ID");
  var request = new RestRequest(Method.PATCH);
  request.AddHeader("authorization", "Bearer MGMT_API_ACCESS_TOKEN");
  request.AddHeader("content-type", "application/json");
  request.AddParameter("application/json", "{"user_metadata": {"picture": "https://example.com/some-image.png"}}", ParameterType.RequestBody);
  IRestResponse response = client.Execute(request);
  ```

  ```go Go theme={null}
  package main

  import (
  	"fmt"
  	"strings"
  	"net/http"
  	"io/ioutil"
  )

  func main() {

  	url := "https://{yourDomain}/api/v2/users/USER_ID"

  	payload := strings.NewReader("{"user_metadata": {"picture": "https://example.com/some-image.png"}}")

  	req, _ := http.NewRequest("PATCH", url, payload)

  	req.Header.Add("authorization", "Bearer MGMT_API_ACCESS_TOKEN")
  	req.Header.Add("content-type", "application/json")

  	res, _ := http.DefaultClient.Do(req)

  	defer res.Body.Close()
  	body, _ := ioutil.ReadAll(res.Body)

  	fmt.Println(res)
  	fmt.Println(string(body))

  }
  ```

  ```java Java theme={null}
  HttpResponse<String> response = Unirest.patch("https://{yourDomain}/api/v2/users/USER_ID")
    .header("authorization", "Bearer MGMT_API_ACCESS_TOKEN")
    .header("content-type", "application/json")
    .body("{"user_metadata": {"picture": "https://example.com/some-image.png"}}")
    .asString();
  ```

  ```javascript Node.JS theme={null}
  var axios = require("axios").default;

  var options = {
    method: 'PATCH',
    url: 'https://{yourDomain}/api/v2/users/USER_ID',
    headers: {
      authorization: 'Bearer MGMT_API_ACCESS_TOKEN',
      'content-type': 'application/json'
    },
    data: {user_metadata: {picture: 'https://example.com/some-image.png'}}
  };

  axios.request(options).then(function (response) {
    console.log(response.data);
  }).catch(function (error) {
    console.error(error);
  });
  ```

  ```php PHP theme={null}
  $curl = curl_init();

  curl_setopt_array($curl, [
    CURLOPT_URL => "https://{yourDomain}/api/v2/users/USER_ID",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "PATCH",
    CURLOPT_POSTFIELDS => "{"user_metadata": {"picture": "https://example.com/some-image.png"}}",
    CURLOPT_HTTPHEADER => [
      "authorization: Bearer MGMT_API_ACCESS_TOKEN",
      "content-type: application/json"
    ],
  ]);

  $response = curl_exec($curl);
  $err = curl_error($curl);

  curl_close($curl);

  if ($err) {
    echo "cURL Error #:" . $err;
  } else {
    echo $response;
  }
  ```

  ```python Python theme={null}
  import http.client

  conn = http.client.HTTPSConnection("")

  payload = "{"user_metadata": {"picture": "https://example.com/some-image.png"}}"

  headers = {
      'authorization': "Bearer MGMT_API_ACCESS_TOKEN",
      'content-type': "application/json"
      }

  conn.request("PATCH", "/{yourDomain}/api/v2/users/USER_ID", payload, headers)

  res = conn.getresponse()
  data = res.read()

  print(data.decode("utf-8"))
  ```

  ```ruby Ruby theme={null}
  require 'uri'
  require 'net/http'
  require 'openssl'

  url = URI("https://{yourDomain}/api/v2/users/USER_ID")

  http = Net::HTTP.new(url.host, url.port)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE

  request = Net::HTTP::Patch.new(url)
  request["authorization"] = 'Bearer MGMT_API_ACCESS_TOKEN'
  request["content-type"] = 'application/json'
  request.body = "{"user_metadata": {"picture": "https://example.com/some-image.png"}}"

  response = http.request(request)
  puts response.read_body
  ```
</AuthCodeGroup>

## Use Actions

To ensure that the picture from the `user_metadata` is returned in the <Tooltip tip="ID Token: Credential meant for the client itself, rather than for accessing a resource." cta="View Glossary" href="/docs/glossary?term=ID+Token">ID Token</Tooltip>, we'll need to [create a new Action](/docs/customize/actions/write-your-first-action) to check whether the `event.user.user_metadata.picture` attribute is present, and if so, replace the `user.picture` attribute with that value. This ensures that the picture from the `user_metadata` is returned in the `picture` claim of the ID Token.

1. Navigate to [Auth0 Dashboard > Actions > Library](https://manage.auth0.com/#/actions/library), and select **Build Custom**.

2. Enter a descriptive **Name** for your Action (for example, `Change user pictures`), select the `Login / Post Login` trigger because you’ll be adding the Action to the Login flow, then select **Create**.

3. Locate the Actions Code Editor, copy the following JavaScript code into it, and select **Save Draft** to save your changes:

   ```js lines theme={null}
   exports.onExecutePostLogin = async (event, api) => {
     const { picture } = event.user.user_metadata;
     if (picture) {
       // Return the persisted user_metadata.picture in the ID token
       api.idToken.setCustomClaim("picture", picture)
     }
   };
   ```

4. From the Actions Code Editor sidebar, select Test (play icon), then select **Run** to [test your code](/docs/customize/actions/test-actions).

5. When you’re ready for the Action to go live, select **Deploy**.

Finally, add the Action you created to the [Login Flow](https://manage.auth0.com/#/actions/flows/login/). To learn how to attach Actions to Flows, read the "Attach the Action to a flow" section in [Write Your First Action](/docs/customize/actions/write-your-first-action).

## Change default picture for all users

To change the default picture for all users who have not set a profile picture, you can use an Action. For example:

```js lines theme={null}
exports.onExecutePostLogin = async (event, api) => {
  const DEFAULT_PROFILE_IMAGE = '{yourDefaultImageUrl}';
  api.idToken.setCustomClaim("picture", {defaultProfileImage});
};
```

In this Action, the custom picture is returned in the ID Token and overrides any `picture` property that may come from an external identity provider login, such as Google.

## Limitations

The Auth0 data store is limited and to prevent your application's data from exceeding the limits, we recommend that you use an external database to store user pictures. This allows you to keep your Auth0 data store small and to use a more efficient external database to hold the additional data. To learn more, read [User Data Storage](/docs/secure/security-guidance/data-security/user-data-storage).

## Learn more

* [User Profile Structure](/docs/manage-users/user-accounts/user-profiles/user-profile-structure)
* [User Profile Root Attributes](/docs/manage-users/user-accounts/user-profiles/root-attributes)
* [Understand How Metadata Works in User Profiles](/docs/manage-users/user-accounts/metadata)
* [Manage Metadata Using the Management API](/docs/manage-users/user-accounts/metadata/manage-metadata-api)
* [Manage Metadata with Rules](/docs/manage-users/user-accounts/metadata/manage-metadata-rules)
* [Bulk User Imports](/docs/manage-users/user-migration/bulk-user-imports)
