← Back to articles

Label Studio - Local Image Annotation Tool

Path: Computer Tech/Label Studio - Local Image Annotation Tool.mdUpdated: 2/3/2026

Label Studio - Local Image Annotation Tool

Label Studio is an open-source data labeling platform that runs locally. It's useful for annotating images with bounding boxes, polygons, keypoints, and more - then exporting structured JSON for use in other tools or machine learning pipelines.

Installation

macOS (Homebrew)

bash
# Add the HumanSignal tap
brew tap humansignal/tap

# Install Label Studio
brew install humansignal/tap/label-studio

Alternative: pip

bash
pip install label-studio

Data locations

Label Studio stores everything in your user Application Support folder:

ItemPath
SQLite database~/Library/Application Support/label-studio/label_studio.sqlite3
Environment config~/Library/Application Support/label-studio/.env
Uploaded media~/Library/Application Support/label-studio/media/
Exports~/Library/Application Support/label-studio/export/

Starting the server

bash
# Start on default port 8080
label-studio start

# Start on custom port
label-studio start --port 9090

# Start with specific data directory
label-studio start --data-dir /path/to/data

The web interface opens automatically at http://localhost:8080.

First-time setup

  1. Navigate to http://localhost:8080
  2. Click Sign Up to create a local account
  3. Create your first project

Creating a project for image annotation

  1. Click Create Project
  2. Name your project (e.g., "UI Element Annotations")
  3. Go to Labeling Setup tab
  4. Choose a template or create custom XML config

Example: UI element annotation config

xml
<View>
  <Image name="image" value="$image" zoom="true" zoomControl="true"/>
  
  <!-- Keypoints for precise positions -->
  <KeyPointLabels name="keypoints" toName="image">
    <Label value="point" background="#FF0000"/>
    <Label value="knob_center" background="#00FF00"/>
  </KeyPointLabels>
  
  <!-- Rectangles for buttons/regions -->
  <RectangleLabels name="rectangles" toName="image">
    <Label value="button" background="#FF00FF"/>
    <Label value="display" background="#00FFFF"/>
  </RectangleLabels>
  
  <!-- Ellipses for knobs/dials -->
  <EllipseLabels name="ellipses" toName="image">
    <Label value="knob" background="#00FF00"/>
  </EllipseLabels>
  
  <!-- Polygons for irregular shapes -->
  <PolygonLabels name="polygons" toName="image">
    <Label value="region" background="#FFA500"/>
  </PolygonLabels>
</View>

Web UI vs CLI configuration

You can configure the labeling interface two ways:

Option A: Web UI (Project Settings β†’ Labeling Interface)

ProsCons
Visual preview as you editManual per-project setup
Browse Templates for quick startConfig lives in database only
Visual tab for no-code editingHarder to version control
Immediate feedbackCan't batch-apply to new projects

Option B: CLI/API (programmatic)

ProsCons
Scriptable, repeatableNo live preview
Version control your configsRequires API token setup
Batch-create identical projectsMore initial setup
Integrate with ui-annotate wrapperLearning curve

Recommendation:

  • Prototyping: Use Web UI to experiment with templates
  • Production: Export working config, use API to create projects programmatically

Exporting your config from Web UI

Once you've built a config you like in the Web UI:

  1. Go to Settings β†’ Labeling Interface
  2. Copy the XML from the Code tab
  3. Save to a file (e.g., ui-elements.xml)
  4. Use in API calls or ui-annotate wrapper

Importing images

Option 1: Upload via UI

  1. Go to your project
  2. Click Import
  3. Drag and drop images or click to browse

Option 2: Local file storage

For large datasets, configure local storage:

  1. Go to Project Settings β†’ Cloud Storage
  2. Click Add Source Storage
  3. Choose Local files
  4. Set the absolute path to your images folder

Before using local storage, set environment variables:

bash
export LABEL_STUDIO_LOCAL_FILES_SERVING_ENABLED=true
export LABEL_STUDIO_LOCAL_FILES_DOCUMENT_ROOT=/path/to/images
label-studio start

Exporting annotations

Via UI

  1. Go to your project
  2. Click Export
  3. Choose format:
    • JSON - Full Label Studio format
    • JSON-MIN - Simplified format
    • COCO - For object detection
    • YOLO - For YOLO models
    • Pascal VOC - XML format

Via API

bash
# Get your API token from Account & Settings
TOKEN="your-api-token"
PROJECT_ID=1

# Export as JSON
curl -X GET "http://localhost:8080/api/projects/${PROJECT_ID}/export?exportType=JSON" \
  -H "Authorization: Token ${TOKEN}" \
  -o annotations.json

JSON export format

Exported annotations look like this:

json
[
  {
    "id": 1,
    "data": {
      "image": "/data/upload/1/image.png"
    },
    "annotations": [
      {
        "id": 1,
        "result": [
          {
            "id": "abc123",
            "type": "rectanglelabels",
            "value": {
              "x": 10.5,
              "y": 20.3,
              "width": 15.2,
              "height": 8.7,
              "rectanglelabels": ["button"]
            },
            "from_name": "rectangles",
            "to_name": "image"
          }
        ]
      }
    ]
  }
]

Note: Coordinates are percentages (0-100) of image dimensions, not pixels.

Keyboard shortcuts

ActionShortcut
Submit annotationCtrl+Enter
UndoCtrl+Z
RedoCtrl+Shift+Z
Delete selectedBackspace
Select allCtrl+A
Toggle labels panell

API basics

Get API token

  1. Click your email (top right)
  2. Select Account & Settings
  3. Copy the Access Token

List projects

bash
curl -X GET "http://localhost:8080/api/projects/" \
  -H "Authorization: Token ${TOKEN}"

Create project programmatically

bash
curl -X POST "http://localhost:8080/api/projects/" \
  -H "Authorization: Token ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "My Project",
    "label_config": "<View><Image name=\"image\" value=\"$image\"/></View>"
  }'

Import task (image)

bash
curl -X POST "http://localhost:8080/api/projects/1/import" \
  -H "Authorization: Token ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '[{"data": {"image": "https://example.com/image.jpg"}}]'

Running as background service

Start detached

bash
nohup label-studio start --port 8080 > ~/label-studio.log 2>&1 &

Check if running

bash
curl -s http://localhost:8080/api/health
# Returns: {"status": "UP"}

Stop

bash
pkill -f label-studio

Troubleshooting

Port already in use

bash
# Find what's using port 8080
lsof -i :8080

# Kill it
kill -9 <PID>

Database reset

bash
# Delete database to start fresh (WARNING: loses all data)
rm "~/Library/Application Support/label-studio/label_studio.sqlite3"

View logs

bash
# If running in background with nohup
tail -f ~/label-studio.log

ui-annotate CLI wrapper

A custom CLI wrapper exists at ~/Code/github.com/theslyprofessor/ui-annotate/ that simplifies common annotation workflows.

Installation

bash
# Already installed and symlinked
ls -la ~/.local/bin/ui-annotate

Usage

bash
# Start Label Studio and open image for annotation
ui-annotate ~/Downloads/screenshot.png

# Export annotations for an image
ui-annotate --export ~/Downloads/screenshot.png

How it works

  1. Server management: Starts Label Studio as detached process if not running
  2. Single shared project: All images go to "UI Annotations" project (not per-image projects)
  3. Multipart upload: Uploads images via form data (not file:// URLs)
  4. Task tracking: Maps image paths to task IDs in ~/.ui-annotate/projects.json

Configuration files

FilePurpose
~/.ui-annotate/api_tokenStored JWT refresh token
~/.ui-annotate/projects.jsonImage path β†’ task ID mappings

Simplified annotation configs

Named points only (for maps/buildings)

For annotating locations with just named points and text labels:

xml
<View>
  <Image name="image" value="$image" zoom="true" zoomControl="true"/>
  
  <KeyPointLabels name="points" toName="image">
    <Label value="location" background="#FF0000"/>
  </KeyPointLabels>
  
  <TextArea name="description" toName="image" 
            editable="true" 
            perRegion="true"
            placeholder="Enter location name..."/>
</View>

This config:

  • Allows placing red point markers
  • Attaches text description to each point
  • Ideal for: building maps, floor plans, landmarks

Export format for points

json
{
  "result": [
    {
      "type": "keypointlabels",
      "value": {
        "x": 45.2,
        "y": 32.1,
        "keypointlabels": ["location"]
      }
    },
    {
      "type": "textarea",
      "value": {
        "text": ["Bottom of J"]
      }
    }
  ]
}

API authentication deep dive

Token types

Label Studio uses JWT tokens:

TokenPurposeLifetime
Access tokenAPI requestsShort (hours)
Refresh tokenGet new access tokensLong (days)

Getting tokens

  1. UI method: Account & Settings β†’ Access Token (gives refresh token)
  2. API method: Login returns both tokens

Refreshing access token

bash
REFRESH_TOKEN="your-refresh-token"

# Exchange refresh for access token
curl -X POST "http://localhost:8080/api/token/refresh/" \
  -H "Content-Type: application/json" \
  -d "{\"refresh\": \"${REFRESH_TOKEN}\"}"

# Returns: {"access": "new-access-token"}

Using access token

bash
ACCESS_TOKEN="your-access-token"

curl -X GET "http://localhost:8080/api/projects/" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}"

Note: Use Bearer prefix for JWT access tokens, Token prefix for legacy API keys.

Uploading images via multipart form

The most reliable way to add local images (not file:// URLs):

bash
PROJECT_ID=1
ACCESS_TOKEN="your-access-token"
IMAGE_PATH="/path/to/image.png"

curl -X POST "http://localhost:8080/api/projects/${PROJECT_ID}/import" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -F "file=@${IMAGE_PATH}"

This:

  • Uploads the image to Label Studio's media storage
  • Creates a task automatically
  • Returns the task ID for tracking

Links