Skip to main content
This script extracts embedded technical metadata (EXIF, ICC Profile, JFIF, and related fields), writes selected values to a metadata template, and lets you filter those images in a Box Apps dashboard.
You can generate embedded_metadata representations for any file type in Box. The set of attributes depends on the file. Not every file includes every EXIF, JFIF, ICC, or MakerNotes field, and some tools strip this data, so not all files return useful metadata.

Before you start

Complete these Box setup steps before you build. You need:
  • A , or a .
  • A Box application configured with Client Credentials Grant authentication, authorized in the Admin Console, with this scope:
    • Read and write all files and folders stored in Box
  • Python 3.11 or higher. For the agent path, you can also use Node.js 20+, Java 17+, or .NET 8+.
  • For the agent path, a coding agent such as Codex, Claude Code, or Cursor. Installing helps it use current Box APIs.
Keep the metadata template key, folder ID, and enterprise ID handy. The prompt and your .env file need them.
Embedded metadata is available for any format Box can already . The set of attributes depends on the file. Not every image includes every EXIF, JFIF, ICC, or MakerNotes field, and some tools strip this data. embedded_metadata is an on-demand representation: Box generates it the first time you request it.
The metadata template defines the fields you copy from the representation. Create it once, and every file the script processes writes values in this shape.
This step requires Admin access.
  1. Open the Box Admin Console and select Metadata.
  2. Select New and name it Image Metadata.
  3. Add the following fields:
  1. Copy the template key from under the Template Name. You need it for the prompt and for .env. Box also generates a field key from each field name (for example, Camera Make becomes cameraMake). Use those keys in the script.
  2. Select Save.
Image Metadata template in Box with Date/Time, Camera Make, Image Width, Image Height, ISO, Colour Profile, Content Identifier, Rights, and Creator fields.
For a detailed walkthrough, see Customizing Metadata Templates.
Create a dedicated folder in Box for the images you want on the dashboard.
  1. In Box, create a new folder called Photos.
  2. Upload previewable image files to the folder.
  3. Note the folder ID from the URL. For example, if the URL is https://app.box.com/folder/123456789, the folder ID is 123456789.
  4. Share the folder with your application’s service account. This is required because CCG applications act as a separate service account user that does not automatically have access to your content.
Five sample photos in a Box folder, including aerial landscapes, a trophy, and a stadium tunnel, each with a filename and upload date.
Without this step, all API calls return 404 “Not found” errors.To find your service account email, go to the Developer Console, open your app, and look under General Settings for the Service Account ID (it looks like AutomationUser_xxxxx_xxxxxx@boxdevedition.com).Invite this email as a collaborator on the folder with the Editor role. Editor access is required because the app needs to write metadata back to files.

Build with an agent

Gather these values from Before you start:
  • Metadata template key – from the template you created
  • Photos folder ID – from the folder URL
  • Enterprise ID – from the Developer Console, using the icon in the top-right
Choose your stack and copy the prompt. It already lists these as prerequisites, so the agent reads them from environment variables instead of trying to create them. Replace the <TEMPLATE_KEY>, <FOLDER_ID>, and <ENTERPRISE_ID> placeholders if you want the agent to pre-fill .env. Otherwise, leave them and fill .env yourself after scaffolding.
Python + Script

Review generated code before using it in production. Never paste Box credentials into your coding agent.

When the agent finishes, copy .env.example to .env and fill in your client ID, client secret, enterprise ID, metadata template key, and folder ID. Then skip ahead to Run and verify. You can also clone a working sample if you prefer to start from running code:

Python working sample

Clone the sample, add your Box credentials, and run.
Prefer to write the code yourself? See Build by hand below.

Build by hand

Use this path if you prefer to write the code yourself, or if you need a reference when the agent drifts. Complete Before you start first, then follow the steps in order. The samples use the Box Python SDK v10.
  1. Open your terminal and create a new project directory:
  1. Install dependencies:
After activation, your terminal prompt shows (.venv) at the beginning. Every time you open a new terminal window or tab, re-activate the virtual environment with source .venv/bin/activate from the project directory. If you see ModuleNotFoundError, the venv is usually not activated.
  1. Create a .env file to store your credentials, then add the following content. Replace the placeholder values with your actual credentials from the Box Developer Console:
Never commit .env files to version control. Add .env to your .gitignore.
Create the Box client module in your project directory:
Client Credentials Grant is recommended for server-to-server automations where no end user is present. For other authentication options, see the authentication overview.
Create representations.py. list_representations prints every representation Box can generate for that file. fetch_representation requests a specific one with x_rep_hints. Use [embedded_metadata]. You can request more than one representation in a single call by combining hints in that value.A none state means Box has not generated the representation yet. The Box Python SDK does not start or download that representation for you. After get_file_by_id returns the info and content URLs, fetch_representation uses client.make_request so authentication stays on the Box client. It then polls get_file_by_id until the state is success or viewable.
Example list_representations output:
Call fetch_representation with rep_hint="[embedded_metadata]".Example when generation has not started:
The downloaded body is JSON. A JPEG can look like this (many fields omitted):
One sample file produced 114 data points. Files differ in which categories and fields they include.
Create metadata.py. After fetch_representation returns the JSON bytes, this module maps template keys to JSON paths, converts values to the template field types, and writes an enterprise metadata instance.
Creating metadata only succeeds the first time. If the file already has an instance of the template, Box returns 409 Conflict on Metadata Instance, so this function falls back to a JSON-Patch update. That keeps the script safe to re-run on a file you already processed.Use the add operation rather than replace. add sets a value whether or not the field is already present, so the update still succeeds when a file omits some EXIF fields.
Missing fields are OK. Skip them. Once metadata is attached, the extracted fields become searchable, filterable, and visible in the Box web app. You can use to filter by camera make or ISO, or build dashboards in Box Apps.
Create process.py. This lists image files in BOX_FOLDER_ID, fetches embedded_metadata for each one, and writes the mapped fields.
At this point, your project directory should contain the following files:
When you finish scaffolding, continue to Run and verify.

Run and verify

Run the script against the folder you created in Before you start.
  1. Make sure you are in the extract-exif-metadata directory, then start the script:
  2. Check the terminal output. You should see each file processed, the extracted field count, and a confirmation that metadata was created or updated:
  3. Open a file in Box and select the Metadata tab to verify the values were written correctly.

Filter in a Box Apps dashboard

Add a Box Apps dashboard that uses the template. You can then see and filter images on the technical metadata you wrote.
Photo App dashboard listing photos with Date/Time, Camera Make, Image Width, Image Height, and ISO columns, filtered by Location Blog.
You can also generate a summary of image content (objects, locations, people, text, and so on) and store it on the same template so search covers both technical fields and visual content. See . A search like this works across images:
Photo App dashboard filtered by Location Blog and Keywords Anfield, showing three photos with Date/Time, Camera Make, Image Width, and Image Height columns.
You can also embed the same metadata in a custom page with the Box UI Element .

Troubleshooting

Your Python virtual environment is not activated. Run source .venv/bin/activate from the project directory before running any python3 commands. Each new terminal tab needs its own activation.
Check your .env file:
  • Verify BOX_CLIENT_ID and BOX_CLIENT_SECRET match the values in Developer Console > Configuration.
  • Confirm BOX_ENTERPRISE_ID is your enterprise ID (found in Admin Console > Account & Billing, or Developer Console > icon in the top-right > Copy Enterprise ID).
  • Ensure your app is authorized in the Developer Console.
  • Make sure the app type is Client Credentials Grant.
The service account does not have access to the file or folder. Invite the service account email (found in Developer Console > General Settings) as a collaborator with the Editor role on the folder containing your image files.
embedded_metadata is generated on demand. Wait a few seconds and re-run the script. Confirm the file type is one Box can .
Not every file includes every EXIF, XMP, or ICC field. That is expected. Check the downloaded JSON for the categories that file actually contains, then adjust EMBEDDED_METADATA_FIELD_MAP if you need different paths.
The file already has an instance of the template, so creating one fails. This is common when you retest a file that a previous run already processed.Add the 409 fallback shown in Build by hand under 4. Write metadata back to the file so the script updates the existing instance instead of creating a second one.
The template, photos folder, and enterprise ID come from Before you start. An agent cannot create them. Re-paste the prompt with the prerequisites block intact so the agent reads BOX_METADATA_TEMPLATE_KEY, BOX_FOLDER_ID, and BOX_ENTERPRISE_ID from the environment, or follow Build by hand.

Next steps

Invoice intake automation

Run extraction from a webhook so files are tagged as they arrive, instead of on demand.

Content Explorer metadata view

Embed a filterable metadata dashboard in your own app.
Last modified on September 30, 2026