Active and Index support filtering, creating Collections, and by extension, creating Datasets and Projects based on the custom metadata on your data.

Prerequisites

Before you can filter your data or create a Collection based on your data’s custom metadata, the custom metadata must exist in your Annotate Project.

This content applies to custom metadata (clientMetadata), which is the metadata associated with individual data units. This is distinct from videoMetadata that is used to specify video parameters when using Strict client-only access. It is also distinct from patient metadata in DICOM files.

Custom metadata (clientMetadata) is accessed by specifying the dataset using the <dataset_hash>. All Projects that have the specified Dataset attached contain custom metadata.

READ THIS FIRST

While not required, we strongly recommend importing a metadata schema before importing custom metadata into Encord. The process we recommend:

  1. Import a metadata schema. If a metadata schema already exists, you can import metadata. You can run a small piece of code to verify that a metadata schema exists
  2. Import your custom metadata.
Performing multiple schema imports overwrites the current schema with the new schema.

Import Custom Metadata With Video Import

This JSON file imports custom metadata while importing your data into Index from a cloud integration.

Importing with Custom Embeddings

You can import custom embeddings with custom metadata. When importing custom embeddings with custom metadata keep the following in mind:

config is optional when importing your custom embeddings:

"config": {
    "sampling_rate": "<samples-per-second>",
    "keyframe_mode": "frame" or "seconds",
},

If config is not specified, the sampling_rate is 1 frame per second, and the keyframe_mode is frame.

Specifying a sampling_rate of 0 only imports the first frame and all keyframes of your video into Index.

Examples

  • Example - Simple: Imports custom metadata with the video.

  • Example - Advanced: Imports custom metadata, key frames, and custom embeddings. If custom embeddings are not specified, only key frames appear in Active and Index.

Import to Videos already in Index

We recommend importing custom metadata when you import your data, because importing with your data can significantly save you time when importing at scale. However, you can import custom metadata on data that already exists in Encord.

Importing with Custom Embeddings

You can import custom embeddings with custom metadata. When importing custom embeddings with custom metadata keep the following in mind:

config is optional when importing your custom embeddings:

"config": {
    "sampling_rate": "<samples-per-second>",
    "keyframe_mode": "frame" or "seconds",
},

If config is not specified, the sampling_rate is 1 frame per second, and the keyframe_mode is frame.

Specifying a sampling_rate of 0 only imports the first frame and all keyframes of your video into Index.

Examples

Folders and custom metadata

List custom metadata (Folders)

Boilerplate

from encord import EncordUserClient
from encord.orm.storage import StorageFolder, StorageItem, StorageItemType, FoldersSortBy

# Authentication
SSH_PATH = "<file-path-to-ssh-private-key-file>"
FOLDER_HASH = "<unique-folder-id>"

# Authenticate with Encord using the path to your private key
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
    ssh_private_key_path=SSH_PATH,
)

folder = user_client.get_storage_folder(FOLDER_HASH)
items = folder.list_items()

for item in items:
    print (item.uuid, item.client_metadata)

Example

from encord import EncordUserClient
from encord.orm.storage import StorageFolder, StorageItem, StorageItemType, FoldersSortBy

# Authentication
SSH_PATH = "/Users/chris-encord/sdk-ssh-private-key.txt"
FOLDER_HASH = "2a838557-d6f4-4408-a980-64246dc5c56b"

# Authenticate with Encord using the path to your private key
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
    ssh_private_key_path=SSH_PATH,
)

folder = user_client.get_storage_folder(FOLDER_HASH)
items = folder.list_items()

for item in items:
    print (item.uuid, item.client_metadata)

Import custom metadata (Folders)

Before importing custom metadata to Encord, first import a metadata schema. We strongly recommend that you upload your custom metadata to Folders, instead of importing using Datasets. Importing custom metadata to data in folders allows you to filter your data in Index by custom metadata.

After importing or updating custom metadata, verify that your custom metadata (list the data units with custom metadata) applied correctly. Do not simply add a print command after importing or updating your custom metadata.

Import custom metadata to specific data units in a Folder

This code allows you to import custom metadata on specific data units in Index. This code OVERWRITES all existing custom metadata on a data unit.

Boilerplate
# Import dependencies
from encord import EncordUserClient
from encord.orm.storage import StorageFolder, StorageItem, StorageItemType, FoldersSortBy


# Authentication
SSH_PATH = "<file-path-to-ssh-private-key-file>"
FOLDER_HASH = "<unique-folder-id>"

# Authenticate with Encord using the path to your private key
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
    ssh_private_key_path=SSH_PATH,
)

folder = user_client.get_storage_folder(FOLDER_HASH)

# Define a dictionary with item UUIDs and their respective metadata updates
updates = {
    # "<data-unit-id>": {"metadata": "metadata-value"},
    # "<data-unit-id>": {"metadata": False},
    # "<data-unit-id>": {"metadata": "metadata-value"},
    # "<data-unit-id>": {"metadata": True}
}

# Update the storage items based on the dictionary
for item_uuid, metadata in updates.items():
    item = user_client.get_storage_item(item_uuid=item_uuid)
    item.update(client_metadata=metadata)

Example 1
# Import dependencies
from encord import EncordUserClient
from encord.orm.storage import StorageFolder, StorageItem, StorageItemType, FoldersSortBy

# Authentication
SSH_PATH = "/Users/chris-encord/sdk-ssh-private-key.txt"
FOLDER_HASH = "2a838557-d6f4-4408-a980-64246dc5c56b"

# Authenticate with Encord using the path to your private key
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
    ssh_private_key_path=SSH_PATH,
)

folder = user_client.get_storage_folder(FOLDER_HASH)

# Define a dictionary with item UUIDs and their respective metadata updates
updates = {
    # "<data-unit-id>": {"metadata": "metadata-value"},
    # "<data-unit-id>": {"metadata": False}, # examples
    "8ad58157-ca74-4ae4-8f37-a0193430bcac": {"dark": True},
    "f165fe81-1956-4347-81ca-3a3b198f3f23": {"light": False},
    "9bd58157-ca74-4ae4-8f37-a0193431bcba": {"count": "100"},
    "62daaa33-195e-4faf-be5b-8335a239beb6": {"taken_at": "2024-02-24"}
}

# Update the storage items based on the dictionary
for item_uuid, metadata in updates.items():
    item = user_client.get_storage_item(item_uuid=item_uuid)
    item.update(client_metadata=metadata)

Import custom metadata to all data units in a Folder

This code allows you to update ALL custom metadata on ALL data units in a Folder in Index. This code OVERWRITES all existing custom metadata on a data unit.

Boilerplate
# Import dependencies
from encord import EncordUserClient
from encord.orm.storage import StorageFolder, StorageItem, StorageItemType, FoldersSortBy

# Authentication
SSH_PATH = "<file-path-to-ssh-private-key-file>"
FOLDER_HASH = "<unique-folder-id>"

# Authenticate with Encord using the path to your private key
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
    ssh_private_key_path=SSH_PATH,
)

folder = user_client.get_storage_folder(FOLDER_HASH)
items = folder.list_items()

for item in items:
     item.update(client_metadata={"metadata": "value", "metadata": "value"})
Example
# Import dependencies
from encord import EncordUserClient
from encord.orm.storage import StorageFolder, StorageItem, StorageItemType, FoldersSortBy

# Authentication
SSH_PATH = "/Users/chris-encord/sdk-ssh-private-key.txt"
FOLDER_HASH = "2a838557-d6f4-4408-a980-64246dc5c56b"

# Authenticate with Encord using the path to your private key
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
    ssh_private_key_path=SSH_PATH,
)

folder = user_client.get_storage_folder(FOLDER_HASH)
items = folder.list_items()

for item in items:
     item.update(client_metadata={"dark": True, "captured_at": "2024-02-24"})

Update custom metadata

The Specific Data Units code enables you to update custom metadata for specific data units in Index. It does not overwrite all existing custom metadata on a data unit. Instead, it updates metadata that matches existing keys with new values and adds any new custom metadata keys to the data unit without affecting other existing metadata.

The All data units in a Project code updates the custom metadata for all data units in the specified Project. Replace the client_metadata with the metadata you want to update.

Specific data units in Index
# Import dependencies
from encord import EncordUserClient

# Authentication
SSH_PATH = "<private_key_path>"

# Authenticate with Encord using the path to your private key
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
    ssh_private_key_path=SSH_PATH,
)

# Define a dictionary with item UUIDs and their respective metadata updates
updates = {
     "<data-unit-id>": {"metadata": "metadata-value"},
     "<data-unit-id>": {"metadata": False},
     "<data-unit-id>": {"metadata": "metadata-value"},
    # "<data-unit-id>": {"metadata": True}
}

# Update the storage items based on the dictionary
for item_uuid, metadata_update in updates.items():
    item = user_client.get_storage_item(item_uuid=item_uuid)

    # make a copy of the current metadata and update it with the new metadata
    curr_metadata = item.client_metadata.copy()
    curr_metadata.update(metadata_update)

    # update the item with the new metadata
    item.update(client_metadata=curr_metadata)
All data units in a Project
#Import dependencies
from encord.user_client import EncordUserClient

# Authentication
SSH_PATH = "<private_key_path>"

# Authenticate with Encord using the path to your private key
user_client = EncordUserClient.create_with_ssh_private_key(SSH_PATH)

# Specify a Project
project = user_client.get_project("<project_hash>")

for label_row in project.list_label_rows_v2():
    storage_item = user_client.get_storage_item(label_row.backing_item_uuid)

    # Updates the specified client_metadata for all items in the Project.
    storage_item.update(client_metadata={"my": "new dict"})

Bulk custom metadata import to all data units in a Folder

This code allows you to update custom metadata on all data units in a Folder in Index. This code OVERWRITES all existing custom metadata on a data unit.

Using bundle allows you to update up to 1000 label rows at a time.

# Import dependencies
from encord import EncordUserClient
from encord.http.bundle import Bundle
from encord.orm.storage import StorageFolder, StorageItem, StorageItemType, FoldersSortBy

# Authentication
SSH_PATH = "<ssh-private-key>"
FOLDER_HASH = "<unique-folder-id>"

# Authenticate with Encord using the path to your private key
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
    ssh_private_key_path=SSH_PATH,
)

folder = user_client.get_storage_folder(FOLDER_HASH)
items = folder.list_items()

# Use the Bundle context manager
with Bundle() as bundle:
    for item in items:
        # Update each item with client metadata
        item.update(client_metadata={"metadata-1": "value", "metadata-2": False}, bundle=bundle)

Bulk custom metadata import on specific data units

This code allows you to update custom metadata on specific data units in a Folder in Index. This code DOES NOT OVERWRITE existing custom metadata on a data unit. It does overwrite custom metadata with existing values and adds new custom metadata to the data unit.

Using bundle allows you to update up to 1000 label rows at a time.

# Import dependencies
from encord import EncordUserClient
from encord.http.bundle import Bundle
from encord.orm.storage import StorageFolder, StorageItem, StorageItemType, FoldersSortBy

# Authentication
SSH_PATH = "<ssh-private-key>"
FOLDER_HASH = "<unique-folder-id>"

# Authenticate with Encord using the path to your private key
user_client: EncordUserClient = EncordUserClient.create_with_ssh_private_key(
    ssh_private_key_path=SSH_PATH,
)

folder = user_client.get_storage_folder(FOLDER_HASH)
updates = {
    # "<data-unit-id>": {"metadata-1": "metadata-value"},
    # "<data-unit-id>": {"metadata-2": False},
    # "<data-unit-id>": {"metadata-1": "metadata-value"},
    # "<data-unit-id>": {"metadata-2": True}
}

# Use the Bundle context manager
with Bundle() as bundle:
    for storage_item in folder.list_items():
        # Update each item with client metadata
        update = updates[storage_item.uuid]
        storage_item.update(client_metadata=update, bundle=bundle)

Add custom metadata to images in an image group

The following script adds clientMetadata to all images / frames in a specified Image Group.

Esure that you:

  • Replace <private_key_path> with the file path to your private SSH key.
  • Replace <image-group-id> with the File ID (UUID) of the target Image Group.
  • Customize the _get_metadata_for_image function with the clientMetadata you want to add. To add unique metadata for each image, make the function dynamic by passing additional variables.
from uuid import UUID
from encord import EncordUserClient
from encord.http.bundle import Bundle

# Initialize the SDK client
user_client = EncordUserClient.create_with_ssh_private_key(
    ssh_private_key_path="<private_key_path>"
    )

# Replace image-group-id with the File ID of the image group
image_group_uuid = "<image-group-id>"

# Function to define metadata for each image. Can be made dynamic by passing variables.
def _get_metadata_for_image(image):
    return {
        "somekindof": "string",
        "somekindof": "number"
    }

# Fetch the uploaded image group
uploaded_image_group = user_client.get_storage_item(image_group_uuid)

# Retrieve and update metadata for each image in the group
frame_items = uploaded_image_group.get_child_items()

with Bundle() as bundle:
    for frame_item in frame_items:
        # Update client metadata for each image
        frame_item.update(client_metadata=_get_metadata_for_image(frame_item), bundle=bundle)
        print (frame_item.client_metadata)

# Re-fetch and verify updates
updated_frame_items = uploaded_image_group.get_child_items()

for updated_frame_item in updated_frame_items:
    expected_metadata = _get_metadata_for_image(updated_frame_item)
    assert updated_frame_item.client_metadata == expected_metadata

print("Client metadata successfully added and verified for all images in the Image Group.")

Datasets and custom metadata

Before importing custom metadata to Encord, first import a metadata schema.

We strongly recommend that you upload your custom metadata to Folders, instead of importing using Datasets. Importing custom metadata to data in Folders allows you to filter your data in Index by custom metadata.

List custom metadata (Datasets)

The following code lists the custom metadata of all data units in the specified Dataset. The code prints the custom metadata along with the data unit’s index within the dataset.


# Import dependencies
from encord import EncordUserClient
from encord.client import DatasetAccessSettings

# Authenticate with Encord using the path to your private key
client = EncordUserClient.create_with_ssh_private_key(
    ssh_private_key_path="<private_key_path>"
)

# Specify a dataset to read or write metadata to
dataset = client.get_dataset("<dataset_hash>")

# Fetch the dataset's metadata
dataset.set_access_settings(DatasetAccessSettings(fetch_client_metadata=True))

# Read the metadata of all data units in the dataset.
for data_unit, data_row in enumerate(dataset.data_rows):
    print(f"{data_row.client_metadata} - Data Unit: {data_unit}")

Import custom metadata (Datasets)

Before importing custom metadata to Encord, first import a metadata schema. We strongly recommend that you import your custom metadata to Folders, instead of importing to Datasets. Importing custom metadata to data in folders allows you to filter your data in Index by custom metadata.

Import custom metadata to a specific data unit in your Dataset

You can import custom metadata (clientMetadata) to specific data units in the Dataset.

  • Replace <private_key_path> with the path to your private key.
  • Replace <dataset_hash> with the hash of your Dataset.
  • Replace Image1.png and the other file names in the metadata variable with the names of the files in your Dataset to which you want to add metadata.

You can find the <data unit number> by reading all metadata in the Dataset.

Multiple data units
from encord import EncordUserClient
from encord.client import DatasetAccessSettings

# Instantiate Encord client by substituting the path to your private key
user_client = EncordUserClient.create_with_ssh_private_key(
                ssh_private_key_path="<private_key_path>",
            )


# Specify a Dataset to read or write metadata to
dataset = user_client.get_dataset("<dataset_hash>")

# Fetch the dataset's metadata
dataset.set_access_settings(DatasetAccessSettings(fetch_client_metadata=True))

metadata = {
  'Image1.png': {"group-id": "A", 'layout-group': 'A'},
  'Image2.png': {"group-id": "B", 'layout-group': 'A'},
  'Image3.png': {"group-id": "C", 'layout-group': 'B'},
  'Image4.png': {"group-id": "D", 'layout-group': 'B'},
}

for data_row in dataset.data_rows:
  data_row.client_metadata = metadata[data_row['data_title']]
  data_row.save()
  print(data_row.client_metadata)

Import custom metadata (clientMetadata) to all data units in a Dataset

The following code adds the same custom metadata (clientMetadata) to each data unit in the specified dataset. The code prints the custom metadata along with the data units index within the dataset, so that you can verify that the custom metadata was set correctly.


# Import dependencies
from encord import EncordUserClient
from encord.client import DatasetAccessSettings

# Authenticate with Encord using the path to your private key
client = EncordUserClient.create_with_ssh_private_key(
    ssh_private_key_path="<private_key_path>"
)

# Specify a dataset to read or write metadata to
dataset = client.get_dataset("<dataset_hash>")

# Fetch the Dataset's metadata
dataset.set_access_settings(DatasetAccessSettings(fetch_client_metadata=True))

# Add metadata to all data units in the Dataset.
# Replace {"my": "metadata"} with the metadata you want to add
for data_unit, data_row in enumerate(dataset.data_rows):
    data_row.client_metadata = {"my": "metadata"}
    data_row.save()
    print(f"{data_row.client_metadata} - Data Unit: {data_unit}")


Deprecated - Reserved Keywords

Reserved keywords are strings that are set aside for exclusive use. The following keywords are reserved:

  • keyframes

KEYFRAMES

keyframes is reserved for use with frames of interest in videos. Specifying keyframes on specific frames ensures that those frames import into Index and Active. That means frames specified using keyframes are available to filter your frames and for calculating embeddings on your data.

You can include keyframes while importing your videos or after you import your videos.

Import keyframes to Specific Data Units (Folder):

This code allows you to import keyframes on specific videos in Index. This code DOES NOT OVERWRITE all existing custom metadata on a data unit. It does overwrite custom metadata with existing values and adds new custom metadata to the data unit.