Skip to main content
Labels define the object classes you want to annotate, while attributes capture additional properties of those objects. A well-designed label schema is crucial for high-quality annotations.

Understanding Labels

A label represents an annotation class in CVAT. Each label has:
  • Name: Unique identifier for the object class
  • Color: Visual color for annotations (auto-generated if not specified)
  • Type: Shape type constraint (optional)
  • Attributes: Additional properties for labeled objects
  • Sublabels: Nested labels for hierarchical classification

Label Types

Labels can be constrained to specific annotation shapes:
TypeDescriptionUse Case
anyAny shape type (default)General purpose
rectangleBounding boxes onlyObject detection
polygonPolygons onlyPrecise segmentation
polylineLines onlyLane detection, boundaries
pointsPoint annotationsKeypoints, landmarks
ellipseEllipses onlyCircular objects
cuboid3D cuboids3D object detection
maskPixel masksSemantic segmentation
skeletonSkeleton structuresPose estimation
tagFrame-level tagsImage classification

Creating Labels

In Projects

Labels defined at the project level are shared across all tasks: Using the API:
curl -X POST "https://app.cvat.ai/api/projects" \
  -H "Authorization: Token <your-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Autonomous Driving",
    "labels": [
      {
        "name": "car",
        "color": "#ff0000",
        "type": "rectangle"
      },
      {
        "name": "pedestrian",
        "color": "#00ff00",
        "type": "rectangle"
      },
      {
        "name": "road",
        "color": "#0000ff",
        "type": "polygon"
      }
    ]
  }'
Using the SDK:
from cvat_sdk import Client, models

client = Client(url="https://app.cvat.ai")
client.login(("username", "password"))

labels = [
    models.PatchedLabelRequest(
        name="vehicle",
        color="#ff0000",
        type="rectangle"
    ),
    models.PatchedLabelRequest(
        name="lane_marking",
        color="#ffff00",
        type="polyline"
    )
]

project = client.projects.create(
    spec=models.ProjectWriteRequest(
        name="Road Scene Annotation",
        labels=labels
    )
)

In Standalone Tasks

Tasks without a project can have their own labels:
task = client.tasks.create(
    spec=models.TaskWriteRequest(
        name="Custom Task",
        labels=[
            models.PatchedLabelRequest(
                name="defect",
                color="#ff0000"
            )
        ]
    )
)

Using the CLI

# Create project with labels from JSON file
cvat-cli --auth user:password project create \
  --labels labels.json \
  "My Project"

# Inline label definition
cvat-cli --auth user:password task create \
  --labels '[
    {"name": "person", "type": "rectangle"},
    {"name": "bike", "type": "rectangle"}
  ]' \
  "Detection Task"

Label Attributes

Attributes capture additional properties of annotated objects.

Attribute Types

TypeDescriptionExample
checkboxBoolean valueOccluded: true/false
radioSingle selection (deprecated)Use select instead
selectDropdown selectionVehicle type: sedan/suv/truck
numberNumeric valueConfidence: 0-100
textFree-form textLicense plate: ABC123

Mutable vs Immutable

  • Immutable attributes: Set once per object (e.g., vehicle type)
  • Mutable attributes: Can change per frame in tracks (e.g., occlusion state)

Defining Attributes

label_with_attributes = models.PatchedLabelRequest(
    name="car",
    color="#ff0000",
    type="rectangle",
    attributes=[
        # Checkbox attribute
        models.AttributeRequest(
            name="occluded",
            input_type="checkbox",
            mutable=True,  # Can change per frame
            default_value="false",
            values=["false"]  # Checkbox values
        ),
        # Select attribute
        models.AttributeRequest(
            name="vehicle_type",
            input_type="select",
            mutable=False,  # Set once per object
            default_value="sedan",
            values=["sedan", "suv", "truck", "van"]
        ),
        # Number attribute
        models.AttributeRequest(
            name="confidence",
            input_type="number",
            mutable=False,
            default_value="100",
            values=["0", "100", "1"]  # min, max, step
        ),
        # Text attribute
        models.AttributeRequest(
            name="license_plate",
            input_type="text",
            mutable=False,
            default_value="",
            values=[]  # No predefined values
        )
    ]
)
API format:
{
  "name": "car",
  "color": "#ff0000",
  "attributes": [
    {
      "name": "color",
      "input_type": "select",
      "mutable": false,
      "default_value": "unknown",
      "values": ["red", "blue", "white", "black", "unknown"]
    },
    {
      "name": "damaged",
      "input_type": "checkbox",
      "mutable": false,
      "default_value": "false",
      "values": ["false"]
    }
  ]
}

Label Hierarchies (Sublabels)

Create nested label structures for complex classification:
vehicle_label = models.PatchedLabelRequest(
    name="vehicle",
    color="#ff0000",
    type="rectangle",
    sublabels=[
        models.PatchedLabelRequest(
            name="car",
            color="#ff3333",
            type="rectangle"
        ),
        models.PatchedLabelRequest(
            name="truck",
            color="#ff6666",
            type="rectangle"
        ),
        models.PatchedLabelRequest(
            name="motorcycle",
            color="#ff9999",
            type="rectangle"
        )
    ]
)
API format:
{
  "name": "animal",
  "color": "#00ff00",
  "sublabels": [
    {"name": "dog", "color": "#00ff33"},
    {"name": "cat", "color": "#00ff66"},
    {"name": "bird", "color": "#00ff99"}
  ]
}
Sublabels inherit the parent label’s type if not specified. They can have their own attributes.

Skeleton Labels

For pose estimation and keypoint detection:
person_skeleton = models.PatchedLabelRequest(
    name="person",
    type="skeleton",
    svg="""<line x1='0' y1='0' x2='10' y2='10' />...""",
    sublabels=[
        models.PatchedLabelRequest(name="head"),
        models.PatchedLabelRequest(name="left_shoulder"),
        models.PatchedLabelRequest(name="right_shoulder"),
        models.PatchedLabelRequest(name="left_elbow"),
        # ... more keypoints
    ]
)
The svg field defines connections between keypoints.

Updating Labels

Update Project Labels

project = client.projects.retrieve(project_id=1)

# Add new label
project.update(models.PatchedProjectWriteRequest(
    labels=[
        # Existing label (must include ID)
        models.PatchedLabelRequest(
            id=10,
            name="existing_label"
        ),
        # New label (no ID)
        models.PatchedLabelRequest(
            name="new_label",
            color="#ff00ff"
        )
    ]
))

# Update existing label
project.update(models.PatchedProjectWriteRequest(
    labels=[
        models.PatchedLabelRequest(
            id=10,
            name="updated_name",
            color="#00ff00"
        )
    ]
))
Using the API:
curl -X PATCH "https://app.cvat.ai/api/projects/1" \
  -H "Authorization: Token <your-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "labels": [
      {"id": 10, "name": "updated_car"},
      {"name": "new_label", "color": "#ff00ff"}
    ]
  }'

Delete Labels

To delete a label, mark it with deleted: true:
curl -X PATCH "https://app.cvat.ai/api/projects/1" \
  -H "Authorization: Token <your-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "labels": [
      {"id": 10, "deleted": true}
    ]
  }'
Deleting a label removes all associated annotations. This action cannot be undone.

Retrieving Labels

Get Project Labels

# Using project
project = client.projects.retrieve(project_id=1)
labels = project.get_labels()

for label in labels:
    print(f"Label: {label.name}")
    print(f"  Color: {label.color}")
    print(f"  Type: {label.type}")
    
    # Print attributes
    for attr in label.attributespec_set:
        print(f"  Attribute: {attr.name} ({attr.input_type})")
        if attr.values:
            print(f"    Values: {attr.values}")

Get Task Labels

task = client.tasks.retrieve(task_id=10)
labels = task.get_labels()

# Tasks in projects inherit project labels
if task.project_id:
    print("Labels inherited from project")
else:
    print("Task-specific labels")

Query Labels via API

# Get all labels for a project
curl "https://app.cvat.ai/api/labels?project_id=1" \
  -H "Authorization: Token <your-token>"

# Get all labels for a task
curl "https://app.cvat.ai/api/labels?task_id=10" \
  -H "Authorization: Token <your-token>"

Importing Label Schemas

From JSON File

labels.json:
[
  {
    "name": "person",
    "color": "#ff0000",
    "type": "rectangle",
    "attributes": [
      {
        "name": "age_group",
        "input_type": "select",
        "mutable": false,
        "default_value": "adult",
        "values": ["child", "adult", "senior"]
      }
    ]
  },
  {
    "name": "vehicle",
    "color": "#00ff00",
    "type": "polygon"
  }
]
Using CLI:
cvat-cli --auth user:password project create \
  --labels labels.json \
  "Project from JSON"
Using SDK:
import json

with open("labels.json") as f:
    labels_data = json.load(f)

labels = [models.PatchedLabelRequest(**label) for label in labels_data]

project = client.projects.create(
    spec=models.ProjectWriteRequest(
        name="Imported Labels Project",
        labels=labels
    )
)

From Existing Project

# Copy labels from one project to another
source_project = client.projects.retrieve(project_id=1)
source_labels = source_project.get_labels()

# Convert to creation format (remove IDs)
new_labels = [
    models.PatchedLabelRequest(
        name=label.name,
        color=label.color,
        type=label.type,
        attributes=[
            models.AttributeRequest(
                name=attr.name,
                input_type=attr.input_type,
                mutable=attr.mutable,
                default_value=attr.default_value,
                values=attr.values.split("\n") if attr.values else []
            )
            for attr in label.attributespec_set
        ]
    )
    for label in source_labels
]

target_project = client.projects.create(
    spec=models.ProjectWriteRequest(
        name="Cloned Label Schema",
        labels=new_labels
    )
)

Exporting Label Schemas

import json

project = client.projects.retrieve(project_id=1)
labels = project.get_labels()

# Convert to JSON-serializable format
labels_export = []
for label in labels:
    label_data = {
        "name": label.name,
        "color": label.color,
        "type": label.type,
        "attributes": [
            {
                "name": attr.name,
                "input_type": attr.input_type,
                "mutable": attr.mutable,
                "default_value": attr.default_value,
                "values": attr.values.split("\n") if attr.values else []
            }
            for attr in label.attributespec_set
        ]
    }
    labels_export.append(label_data)

# Save to file
with open("exported_labels.json", "w") as f:
    json.dump(labels_export, f, indent=2)

print("Labels exported to exported_labels.json")

Best Practices

  • Use clear, descriptive names: “pedestrian” not “ped”
  • Avoid ambiguous class boundaries
  • Consider annotation difficulty when splitting classes
  • Balance between specificity and annotator burden
  • rectangle: Fast annotation for bounding boxes
  • polygon: Precise segmentation when needed
  • polyline: Lane markings, boundaries
  • skeleton: Human pose, articulated objects
  • tag: Image-level classification
  • Use select for categorical properties
  • Set mutable=true for properties that change over time
  • Provide default_value to speed annotation
  • Limit attribute count to avoid annotator fatigue
  • Use distinct colors for different classes
  • Maintain color scheme across projects
  • Consider colorblind-friendly palettes
  • Let CVAT auto-generate colors if unsure
  • Start with core classes, add as needed
  • Export label schemas for reuse
  • Document label definitions clearly
  • Communicate changes to annotation team

Example Label Schemas

Object Detection (COCO-style)

[
  {"name": "person", "type": "rectangle"},
  {"name": "bicycle", "type": "rectangle"},
  {"name": "car", "type": "rectangle"},
  {"name": "motorcycle", "type": "rectangle"},
  {"name": "bus", "type": "rectangle"},
  {"name": "truck", "type": "rectangle"}
]

Semantic Segmentation

[
  {"name": "road", "type": "polygon", "color": "#804080"},
  {"name": "sidewalk", "type": "polygon", "color": "#f423e8"},
  {"name": "building", "type": "polygon", "color": "#464646"},
  {"name": "vegetation", "type": "polygon", "color": "#6b8e23"},
  {"name": "sky", "type": "polygon", "color": "#87ceeb"}
]

Document Classification

[
  {
    "name": "document",
    "type": "tag",
    "attributes": [
      {
        "name": "document_type",
        "input_type": "select",
        "values": ["invoice", "receipt", "contract", "form"],
        "default_value": "invoice"
      },
      {
        "name": "language",
        "input_type": "select",
        "values": ["en", "es", "fr", "de"],
        "default_value": "en"
      }
    ]
  }
]

Next Steps

Quality Control

Set up validation and quality metrics

Managing Tasks

Create tasks and upload data

Annotation Tools

Learn annotation tools and shortcuts

API Reference

Complete labels API documentation

Build docs developers (and LLMs) love