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:
Type Description Use Case anyAny shape type (default) General purpose rectangleBounding boxes only Object detection polygonPolygons only Precise segmentation polylineLines only Lane detection, boundaries pointsPoint annotations Keypoints, landmarks ellipseEllipses only Circular objects cuboid3D cuboids 3D object detection maskPixel masks Semantic segmentation skeletonSkeleton structures Pose estimation tagFrame-level tags Image 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
Type Description Example checkboxBoolean value Occluded: true/false radioSingle selection (deprecated) Use select instead selectDropdown selection Vehicle type: sedan/suv/truck numberNumeric value Confidence: 0-100 textFree-form text License 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
Design labels for your use case
Use clear, descriptive names: “pedestrian” not “ped”
Avoid ambiguous class boundaries
Consider annotation difficulty when splitting classes
Balance between specificity and annotator burden
Use appropriate label types
rectangle: Fast annotation for bounding boxes
polygon: Precise segmentation when needed
polyline: Lane markings, boundaries
skeleton: Human pose, articulated objects
tag: Image-level classification
Configure attributes thoughtfully
Maintain color consistency
Use distinct colors for different classes
Maintain color scheme across projects
Consider colorblind-friendly palettes
Let CVAT auto-generate colors if unsure
Plan for schema evolution
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