Skip to main content
This guide covers the core operations for managing CVAT resources using the Python SDK.

Projects

Projects group related tasks and define shared labels.

Creating Projects

from cvat_sdk import Client, models

client = Client(url="cvat.example.com")
client.login(("username", "password"))

# Define project specification
project_spec = models.ProjectWriteRequest(
    name="Self-Driving Car Dataset",
    labels=[
        models.PatchedLabelRequest(
            name="car",
            color="#ff0000",
            type="rectangle"
        ),
        models.PatchedLabelRequest(
            name="pedestrian",
            color="#00ff00",
            type="rectangle"
        ),
        models.PatchedLabelRequest(
            name="traffic_light",
            color="#0000ff",
            type="rectangle"
        )
    ]
)

project = client.projects.create(spec=project_spec)
print(f"Created project {project.id}: {project.name}")

Creating Projects with Dataset

Import a dataset when creating a project:
project = client.projects.create_from_dataset(
    spec=project_spec,
    dataset_path="annotations.zip",
    dataset_format="COCO 1.0",
    conv_mask_to_poly=False  # Keep masks as is
)

Listing Projects

# List all projects
projects = client.projects.list()

for project in projects:
    print(f"Project {project.id}: {project.name}")
    print(f"  Owner: {project.owner.username}")
    print(f"  Created: {project.created_date}")
    print(f"  Tasks: {len(project.tasks) if hasattr(project, 'tasks') else 'N/A'}")

Retrieving a Project

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

print(f"Name: {project.name}")
print(f"Labels: {len(project.labels)}")
print(f"Status: {project.status}")

Updating Projects

# Update project name
project.update(models.PatchedProjectWriteRequest(name="Updated Project Name"))

# Refresh project data from server
project.fetch()

Working with Project Resources

# Get project tasks
tasks = project.get_tasks()
for task in tasks:
    print(f"Task {task.id}: {task.name}")

# Get project labels
labels = project.get_labels()
for label in labels:
    print(f"Label: {label.name} (ID: {label.id})")

# Get project annotations
annotations = project.get_annotations()
print(f"Total shapes: {len(annotations.shapes)}")
print(f"Total tags: {len(annotations.tags)}")

# Get project preview
preview = project.get_preview()
from PIL import Image
im = Image.open(preview)
im.show()

Exporting Project Dataset

# Export in various formats
project.export_dataset(
    format_name="COCO 1.0",
    filename="project_export.zip"
)

# Export with custom save image parameter
project.export_dataset(
    format_name="YOLO 1.1",
    filename="yolo_export.zip",
    save_images=True
)

Importing Dataset to Project

project.import_dataset(
    format_name="COCO 1.0",
    filename="dataset.zip",
    conv_mask_to_poly=True  # Convert masks to polygons
)

Project Backup and Restore

# Download project backup
project.download_backup("project_backup.zip")

# Restore project from backup
restored_project = client.projects.create_from_backup(
    filename="project_backup.zip"
)

Deleting Projects

# Delete a single project
project.remove()

# Delete multiple projects by ID
client.projects.remove_by_ids([123, 456, 789])

Tasks

Tasks contain the actual data (images/videos) to be annotated.

Creating Tasks

from cvat_sdk.core.proxies.tasks import ResourceType

# Define task specification
task_spec = models.TaskWriteRequest(
    name="Street Images - Batch 1",
    project_id=project.id,  # Optional: link to project
    # If not in project, define labels here:
    # labels=[...]
)

# Create task with local files
task = client.tasks.create_from_data(
    spec=task_spec,
    resources=["img1.jpg", "img2.jpg", "img3.jpg"],
    resource_type=ResourceType.LOCAL,
    data_params={
        "image_quality": 95,
        "chunk_size": 100,
        "sorting_method": "lexicographical"
    }
)

print(f"Created task {task.id}: {task.name}")

Resource Types

Tasks support three resource types:
from cvat_sdk.core.proxies.tasks import ResourceType

# Local files from your machine
task = client.tasks.create_from_data(
    spec=task_spec,
    resources=["path/to/images/img1.jpg", "path/to/images/img2.jpg"],
    resource_type=ResourceType.LOCAL
)

# Remote files (URLs)
task = client.tasks.create_from_data(
    spec=task_spec,
    resources=[
        "https://example.com/image1.jpg",
        "https://example.com/image2.jpg"
    ],
    resource_type=ResourceType.REMOTE
)

# Server share files
task = client.tasks.create_from_data(
    spec=task_spec,
    resources=[
        "share/dataset1/img1.jpg",
        "share/dataset1/img2.jpg"
    ],
    resource_type=ResourceType.SHARE
)

Listing Tasks

# List all tasks
tasks = client.tasks.list()

# Filter tasks by project
project_tasks = [t for t in tasks if t.project_id == project.id]

for task in tasks:
    print(f"Task {task.id}: {task.name}")
    print(f"  Size: {task.size} frames")
    print(f"  Status: {task.status}")
    print(f"  Mode: {task.mode}")

Retrieving a Task

task = client.tasks.retrieve(task_id=456)

print(f"Name: {task.name}")
print(f"Project ID: {task.project_id}")
print(f"Size: {task.size}")
print(f"Mode: {task.mode}")
print(f"Owner: {task.owner.username}")

Updating Tasks

# Update task properties
task.update(models.PatchedTaskWriteRequest(
    name="Updated Task Name",
    subset="train"  # Set dataset subset
))

# Fetch latest data
task.fetch()

Adding Data to Existing Tasks

# Upload additional images
task.upload_data(
    resources=["new_img1.jpg", "new_img2.jpg"],
    resource_type=ResourceType.LOCAL,
    params={
        "image_quality": 90,
        "sorting_method": "natural"
    },
    wait_for_completion=True
)

Working with Task Frames

# Get task metadata
meta = task.get_meta()
print(f"Total frames: {len(meta.frames)}")
print(f"Image quality: {meta.image_quality}")

# Get frame information
frames_info = task.get_frames_info()
for frame in frames_info[:5]:  # First 5 frames
    print(f"Frame {frame.frame}: {frame.name} ({frame.width}x{frame.height})")

# Get a specific frame
frame_bytes = task.get_frame(frame_id=0, quality="original")
from PIL import Image
img = Image.open(frame_bytes)
img.show()

# Get task preview
preview_bytes = task.get_preview()
preview = Image.open(preview_bytes)
preview.show()

# Download multiple frames
task.download_frames(
    frame_ids=[0, 1, 2, 3, 4],
    outdir="downloaded_frames",
    quality="original",
    filename_pattern="frame_{frame_id:06d}{frame_ext}"
)

# Download a chunk
with open("chunk_0.zip", "wb") as f:
    task.download_chunk(chunk_id=0, output_file=f, quality="compressed")

Removing Frames

# Remove specific frames by ID
task.remove_frames_by_ids([5, 10, 15])

Working with Task Jobs

# Get all jobs in a task
jobs = task.get_jobs()

for job in jobs:
    print(f"Job {job.id}")
    print(f"  Status: {job.status}")
    print(f"  Stage: {job.stage}")
    print(f"  Start frame: {job.start_frame}")
    print(f"  Stop frame: {job.stop_frame}")
    print(f"  Assignee: {job.assignee.username if job.assignee else 'Unassigned'}")

Working with Task Labels

# Get task labels
labels = task.get_labels()

for label in labels:
    print(f"Label: {label.name} (ID: {label.id})")
    print(f"  Type: {label.type}")
    print(f"  Color: {label.color}")
    if label.attributes:
        print(f"  Attributes: {[a.name for a in label.attributes]}")

Task Annotations

# Get annotations
annotations = task.get_annotations()

print(f"Shapes: {len(annotations.shapes)}")
print(f"Tags: {len(annotations.tags)}")
print(f"Tracks: {len(annotations.tracks)}")

# Set (replace all) annotations
new_annotations = models.LabeledDataRequest(
    shapes=[
        models.LabeledShapeRequest(
            type="rectangle",
            frame=0,
            label_id=labels[0].id,
            points=[100.0, 100.0, 200.0, 200.0],
            attributes=[]
        )
    ],
    tags=[],
    tracks=[]
)
task.set_annotations(new_annotations)

# Update (add/modify/delete) annotations
from cvat_sdk.core.proxies.annotations import AnnotationUpdateAction

# Add new shapes
task.update_annotations(
    models.PatchedLabeledDataRequest(
        shapes=[
            models.LabeledShapeRequest(
                type="polygon",
                frame=1,
                label_id=labels[0].id,
                points=[10.0, 10.0, 20.0, 10.0, 20.0, 20.0, 10.0, 20.0],
                attributes=[]
            )
        ]
    ),
    action=AnnotationUpdateAction.CREATE
)

# Update existing annotations
task.update_annotations(
    models.PatchedLabeledDataRequest(
        shapes=[
            models.LabeledShapeRequest(
                id=12345,  # Existing shape ID
                type="rectangle",
                frame=0,
                label_id=labels[0].id,
                points=[150.0, 150.0, 250.0, 250.0],
                attributes=[]
            )
        ]
    ),
    action=AnnotationUpdateAction.UPDATE
)

# Delete specific annotations
task.remove_annotations(ids=[12345, 67890])

# Delete all annotations
task.remove_annotations()

Importing Annotations

# Import annotations from file
task.import_annotations(
    format_name="YOLO 1.1",
    filename="annotations.zip"
)

# With mask to polygon conversion
task.import_annotations(
    format_name="COCO 1.0",
    filename="coco_annotations.json",
    conv_mask_to_poly=True
)

Exporting Task Dataset

# Export annotations and data
task.export_dataset(
    format_name="CVAT for images 1.1",
    filename="task_export.zip"
)

# Export only annotations
task.export_dataset(
    format_name="COCO 1.0",
    filename="coco_export.json",
    save_images=False
)

Task Backup and Restore

# Download task backup
task.download_backup("task_backup.zip")

# Create task from backup
restored_task = client.tasks.create_from_backup(
    filename="task_backup.zip"
)

Deleting Tasks

# Delete single task
task.remove()

# Delete multiple tasks
client.tasks.remove_by_ids([123, 456, 789])

Jobs

Jobs are subdivisions of tasks assigned to annotators.

Listing Jobs

# List all jobs
jobs = client.jobs.list()

# Get jobs for a specific task
task_jobs = task.get_jobs()

for job in jobs:
    print(f"Job {job.id}")
    print(f"  Task: {job.task_id}")
    print(f"  Status: {job.status}")
    print(f"  Stage: {job.stage}")
    print(f"  Assignee: {job.assignee.username if job.assignee else 'None'}")

Retrieving a Job

job = client.jobs.retrieve(job_id=789)

print(f"Job {job.id}")
print(f"Task ID: {job.task_id}")
print(f"Frame range: {job.start_frame} - {job.stop_frame}")
print(f"Status: {job.status}")
print(f"Stage: {job.stage}")

Updating Jobs

# Update job properties
job.update(models.PatchedJobWriteRequest(
    status="completed",
    stage="acceptance",
    assignee=user_id
))

job.fetch()

Working with Job Frames

# Get job metadata
meta = job.get_meta()
frames_info = job.get_frames_info()

# Get specific frame
frame_bytes = job.get_frame(frame_id=job.start_frame)

# Download frames
job.download_frames(
    frame_ids=list(range(job.start_frame, job.stop_frame + 1)),
    outdir="job_frames"
)

# Remove frames
job.remove_frames_by_ids([10, 20])

Job Annotations

# Get job annotations
annotations = job.get_annotations()

# Set annotations
job.set_annotations(new_annotations)

# Update annotations
job.update_annotations(partial_annotations)

# Import annotations
job.import_annotations(
    format_name="COCO 1.0",
    filename="job_annotations.json"
)

# Export job dataset
job.export_dataset(
    format_name="YOLO 1.1",
    filename="job_export.zip"
)

Job Issues

# Get issues for a job
issues = job.get_issues()

for issue in issues:
    print(f"Issue {issue.id}: {issue.message}")
    print(f"  Frame: {issue.frame}")
    print(f"  Position: {issue.position}")
    print(f"  Resolved: {issue.resolved}")

Job Labels

# Get labels available in the job
labels = job.get_labels()

for label in labels:
    print(f"Label: {label.name} (ID: {label.id})")

Progress Reporting

Many operations support progress reporting with tqdm:
from tqdm import tqdm
from cvat_sdk.core.progress import ProgressReporter

# Create task with progress bar
with tqdm(desc="Uploading images", unit="bytes") as pbar:
    task = client.tasks.create_from_data(
        spec=task_spec,
        resources=image_files,
        pbar=pbar
    )

# Import annotations with progress
with tqdm(desc="Importing annotations") as pbar:
    task.import_annotations(
        format_name="COCO 1.0",
        filename="annotations.json",
        pbar=pbar
    )

Next Steps

Build docs developers (and LLMs) love