Attachments

Developer guide for importing attachments and image overlay layers

Attachments can add supplementary content to any asset to help provide additional context for your labeling team. An attachment applies to an individual asset and may comprise an image, video, text, or HTML content. Markdown rendering is supported for attachments, allowing you to use to format text, add links, and include images within attachments. Multiple attachments can be linked to an singular data row.

Supported attachment types

TypeValueDescription
IMAGEURL of Image (PNG/JPG) (HTTPS or IAM delegated access path)Labelers can see the attached image(s) while labeling the primary data row
VIDEOURL of Video (MP4) (HTTPS or IAM delegated access path)Labelers can see the attached video(s) while labeling the primary data row
RAW_TEXTText string or hyperlink (see below for cloud-hosted text files)Labelers can see the attached text or hyperlink while labeling the primary data row

If passing a hyperlink, we will show a clickable hyperlink. If you want to display text from a URL endpoint, please use the TEXT_URL type.
TEXT_URLURL of a text file (HTTPS or IAM delegated access path)Labelers can see the attached text from the linked text URL while labeling the primary data row
HTMLURL of an HTML file (HTTPS or IAM delegated access path)Renders HTML in an iframe as an attachment. Labelers can see and interact with the attached HTML widget while labeling the primary data row.
IMAGE_OVERLAYURL of the image layer (PNG/JPG) (HTTPS or IAM delegated access path).A visualization tool designed to help you view the asset to be labeled in different ways by adding image layers over the asset.
PDF_URLURL of the PDF file (HTTPS or IAM delegated access path)Labelers can see the attached document while labeling the primary data row

When using an IAM delegated access path, the attachment must utilize the same cloud storage integration as the data row to which the asset is attached.

🚧

Special character handling

Please note that certain characters like #,<, > and || are not supported in URLs and should be avoided in your file names to prevent loading issues.

Please refer to https://datatracker.ietf.org/doc/html/rfc2396#section-2.4.3 on URI standards.

A good test for the handling of special characters is to test URLs in your browser address bar — if the URL doesn't load properly in your browser, it won't load in Labelbox.

Create an attachment

Attachments are created on a DataRow object. The required arguments for creating an attachment are the attachment_type and attachment_value. You can also name an attachment via the attribute attachment_name.

data_row.create_attachment(
  attachment_type="RAW_TEXT",
  attachment_value="IOWA, Zone 2232, June 2022",
  # optionally, supply a name for the attachment
  attachment_name="<sample_name>"
)

Create a data row with multiple attachments

Use the code snippet below to create a dataset, create a data row, and add attachments to the data row.

# create a new dataset
dataset = client.create_dataset(name="Data Row attachment example")

# create a data row
data_row = dataset.create_data_row(
  row_data="https://storage.googleapis.com/labelbox-sample-datasets/Docs/basic.jpg",
  global_key="<unique_global_key>"
)

# create multiple attachments
data_row.create_attachment(attachment_type="RAW_TEXT", attachment_value="IOWA, Zone 2232, June 2022 [Text string]")
data_row.create_attachment(attachment_type="RAW_TEXT", attachment_value="https://storage.googleapis.com/labelbox-sample-datasets/Docs/text_attachment.txt", attachment_name="IOWA, Zone 2232")
data_row.create_attachment(attachment_type="TEXT_URL", attachment_value="https://storage.googleapis.com/labelbox-sample-datasets/Docs/text_attachment.txt")
data_row.create_attachment(attachment_type="IMAGE", attachment_value="https://storage.googleapis.com/labelbox-sample-datasets/Docs/disease_attachment.jpeg")
data_row.create_attachment(attachment_type="VIDEO", attachment_value="https://storage.googleapis.com/labelbox-sample-datasets/Docs/drone_video.mp4")
data_row.create_attachment(attachment_type="HTML", attachment_value="https://storage.googleapis.com/labelbox-sample-datasets/Docs/windy.html")

JSON format

Use the following format to include attachments in a JSON import file.

[
    {
      "row_data": "https://lb-test-data.s3.us-west-1.amazonaws.com/image-samples/sample-image-1.jpg",
      "global_key": "https://lb-test-data.s3.us-west-1.amazonaws.com/image-samples/sample-image-1.jpg",
      "media_type": "IMAGE",
      "metadata_fields": [{"schema_id": "cko8s9r5v0001h2dk9elqdidh", "value": "tag_string"}],
      "attachments": [
            {
                "type": "RAW_TEXT",
                "value": "IOWA, Zone 2232, June 2022 [Text string]",
                "name": "IOWA, Zone 2232")
            },
            {
                "type": "RAW_TEXT",
                "value": "https://storage.googleapis.com/labelbox-sample-datasets/Docs/text_attachment.txt"
            },
            {
                "type": "TEXT_URL",
                "value": "https://storage.googleapis.com/labelbox-sample-datasets/Docs/text_attachment.txt"
            },
            {
                "type": "IMAGE",
                "value": "https://storage.googleapis.com/labelbox-sample-datasets/Docs/disease_attachment.jpeg"
            },
            {
                "type": "VIDEO",
                "value": "https://storage.googleapis.com/labelbox-sample-datasets/Docs/drone_video.mp4"
            },
            {
                "type": "HTML",
                "value": "https://storage.googleapis.com/labelbox-sample-datasets/Docs/windy.html"
            }
        ]
    }
]
[
     {
       "row_data": "https://lb-test-data.s3.us-west-1.amazonaws.com/video-samples/sample-video-1.mp4",
       "global_key": "https://lb-test-data.s3.us-west-1.amazonaws.com/video-samples/sample-video-1.mp4",
       "media_type": "VIDEO",
       "metadata_fields": [{"schema_id": "cko8s9r5v0001h2dk9elqdidh", "value": "tag_string"}],
       "attachments": [
             {
                 "type": "RAW_TEXT",
                 "value": "Some sample text"
             },
             {
                 "type": "RAW_TEXT",
                 "value": "Some more sample text"
             }
         ]
     }
]
[
     {
       "row_data": "https://lb-test-data.s3.us-west-1.amazonaws.com/text-samples/sample-text-1.txt",
       "global_key": "https://lb-test-data.s3.us-west-1.amazonaws.com/text-samples/sample-text-1.txt",
       "media_type": "TEXT",
       "metadata_fields": [{"schema_id": "cko8s9r5v0001h2dk9elqdidh", "value": "tag_string"}],
       "attachments": [
             {
                 "type": "RAW_TEXT",
                 "value": "Some sample text"
             },
             {
                 "type": "RAW_TEXT",
                 "value": "Some more sample text"
             }
         ]
     }
]

[
  {
    "row_data":{
      "tile_layer_url": "https://s3-us-west-1.amazonaws.com/lb-tiler-layers/mexico_city/{z}/{x}/{y}.png",
      "bounds": [
        [
          19.405662413477728,
          -99.21052827588443
        ],
        [
          19.400498983095076,
          -99.20534818927473
        ]
      ],
      "min_zoom": 12,
      "max_zoom": 20,
      "epsg": "EPSG4326",
      "alternative_layers": [
        {
          "tile_layer_url": "https://api.mapbox.com/styles/v1/mapbox/satellite-streets-v11/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw",
          "name": "Satellite"
        },
        {
          "tile_layer_url": "https://api.mapbox.com/styles/v1/mapbox/navigation-guidance-night-v4/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw",
          "name": "Guidance"
        }
      ]
    },
    "global_key": "https://s3-us-west-1.amazonaws.com/lb-tiler-layers/mexico_city/{z}/{x}/{y}.png",
    "media_type": "TMS_GEO",
    "metadata_fields": [{"schema_id": "cko8s9r5v0001h2dk9elqdidh", "value": "tag_string"}],
    "attachments": [
      {
        "type": "TEXT_URL", "value": "https://storage.googleapis.com/labelbox-sample-datasets/Docs/text_attachment.txt"
      }
    ]
  }
]
[
  {
    "row_data": "https://lb-test-data.s3.us-west-1.amazonaws.com/audio-samples/sample-audio-1.mp3",
    "global_key": "https://lb-test-data.s3.us-west-1.amazonaws.com/audio-samples/sample-audio-1.mp3",
    "media_type": "AUDIO",
    "metadata_fields": [{"schema_id": "cko8s9r5v0001h2dk9elqdidh", "value": "tag_string"}],
    "attachments": [
      {
        "type": "VIDEO", "value": "https://storage.googleapis.com/labelbox-sample-datasets/Docs/drone_video.mp4" 
      }
    ]
  },
  {
    "row_data": "https://lb-test-data.s3.us-west-1.amazonaws.com/audio-samples/sample-audio-2.mp3",
    "global_key": "https://lb-test-data.s3.us-west-1.amazonaws.com/audio-samples/sample-audio-2.mp3",
    "media_type": "AUDIO",
    "metadata_fields": [{"schema_id": "cko8s9r5v0001h2dk9elqdidh", "value": "tag_string"}],
    "attachments": [
      {
        "type": "TEXT_URL", "value": "https://storage.googleapis.com/labelbox-sample-datasets/Docs/text_attachment.txt"
      }
    ]
  }
]
[
  {
    "row_data": {
      "pdf_url": "https://lb-test-data.s3.us-west-1.amazonaws.com/document-samples/sample-document-1.pdf",
      "text_layer_url": "https://lb-test-data.s3.us-west-1.amazonaws.com/document-samples/sample-document-custom-text-layer.json"
    },
    "global_key": "https://lb-test-data.s3.us-west-1.amazonaws.com/document-samples/sample-document-1.pdf",
    "media_type": "PDF",
    "metadata_fields": [{"schema_id": "cko8s9r5v0001h2dk9elqdidh", "value": "tag_string"}],
    "attachments": [
      {
        "type": "HTML", "value": "https://www.wikipedia.org/" 
      }
    ]
  },
  {
    "row_data": {
      "pdf_url": "https://lb-test-data.s3.us-west-1.amazonaws.com/document-samples/sample-document-2.pdf",
      "text_layer_url": "https://lb-test-data.s3.us-west-1.amazonaws.com/document-samples/sample-document-2-custom-text-layer.json"
    },
    "global_key": "https://lb-test-data.s3.us-west-1.amazonaws.com/document-samples/sample-document-2.pdf",
    "media_type": "PDF",
    "metadata_fields": [{"schema_id": "cko8s9r5v0001h2dk9elqdidh", "value": "tag_string"}],
    "attachments": [
      {
        "type": "TEXT_URL", "value": "https://storage.googleapis.com/labelbox-sample-datasets/Docs/text_attachment.txt"
      }
    ]
  }
]
[
  {
    "row_data": "https://lb-test-data.s3.us-west-1.amazonaws.com/conversation-samples/sample-conversation-1.json",
    "global_key": "https://lb-test-data.s3.us-west-1.amazonaws.com/conversation-samples/sample-conversation-1.json",
    "media_type": "CONVERSATIONAL",
    "metadata_fields": [{"schema_id": "cko8s9r5v0001h2dk9elqdidh", "value": "tag_string"}],
    "attachments": [
      {
        "type": "TEXT_URL", "value": "https://storage.googleapis.com/labelbox-sample-datasets/Docs/text_attachment.txt"
      }
    ]
  }
]

Create an image overlay

Image overlays are created as attachments on a data row. Only images may be attached as overlays, and they may only be attached to image assets. A maximum of 10 layers may be added per data row.

data_row.create_attachment(
  attachment_type="IMAGE_OVERLAY",
  attachment_value="https://storage.googleapis.com/labelbox-sample-datasets/Docs/rgb.jpg",
  # optionally, supply a name for the image overlay
  attachment_name="<image_overlay_name>"
)

JSON format

Use the following format to include image overlays in a JSON import file.

[
    {
      "row_data": "https://lb-test-data.s3.us-west-1.amazonaws.com/image-samples/sample-image-1.jpg",
      "global_key": "https://lb-test-data.s3.us-west-1.amazonaws.com/image-samples/sample-image-1.jpg",
      "media_type": "IMAGE",
      "attachments": [
            {
                "type": "IMAGE_OVERLAY",
                "value": "https://storage.googleapis.com/labelbox-sample-datasets/Docs/rgb.jpg",
                "name": "RGB"
            },
            {
                "type": "IMAGE_OVERLAY",
                "value": "https://storage.googleapis.com/labelbox-sample-datasets/Docs/cir.jpg",
                "name": "CIR"
            },
            {
                "type": "IMAGE_OVERLAY",
                "value": "https://storage.googleapis.com/labelbox-sample-datasets/Docs/weeds.jpg",
                "name": "Weeds"
            }
        ]
    }
]

Get an attachment

# relationship to many AssetAttachment objects
attachments = data_row.attachments()

# inspect one attachment
next(attachments)

# inspect all attachments
for attachment in attachments:
  print(attachment)

# for ease of use, you can convert the paginated collection to a list
attachments = list(attachments)

# Display the details of one particular attachment
attachment = attachments[0]
print(f"type: {attachment.attachment_type}",
      f"value: {attachment.attachment_value}",
      f"name: {attachment.attachment_name}",
      sep='\n')

Update an attachment

You can amend one or more attributes between name, type and value.
Note that attributes can only be updated to non-empty values.

# 1. Select the attachment(s) to update
attachments_to_update = [attachment for attachment 
                         in data_row.attachments()
                         if attachment.attachment_type == "RAW_TEXT" 
                         and attachment.attachment_value.startswith("https")]

# 2. Update the attachment
# Change one attribute:
for index, attachment in enumerate(attachments_to_update, start=1):
  attachment.update(name=f"Example of raw text {index}")

# Change multiple attributes:
for attachment in attachments_to_update:
  attachment.update(name="Example of text url", type="TEXT_URL")

Delete an attachment

Be cautious when you delete an attachment, as this operation is irreversible.

# 1. Select the attachment(s) to delete
attachments_to_delete = [attachment for attachment 
                         in data_row.attachments()
                         if attachment.attachment_type == "RAW_TEXT"]

# 2. Delete the attachment(s)
for attachment in attachments_to_delete:
  attachment.delete()

Delete all attachments for a data row

You can utilise a bulk method to delete all the attachments of a data row at once.
Here again, be cautious as there is no rollback possible.

dataset = data_row.dataset()
dataset.upsert_data_rows([{ 'key': lb.UniqueId(data_row.uid), 'attachments': [] }])