Skip to main content

Search

screenpipe provides powerful search across all your captured screen and audio data with natural language queries, time-based filters, and content-type filtering.

Search API

curl "http://localhost:3030/search?q=meeting+notes&limit=10"

Query Parameters

q
string
Search query text. Searches both OCR text and audio transcriptions.
limit
integer
default:"20"
Number of results to return (max 1000).
offset
integer
default:"0"
Pagination offset.
content_type
enum
Filter by content type:
  • all (default)
  • ocr (screen text only)
  • audio (transcriptions only)
  • ui (UI events)
start_time
datetime
Start of time range (ISO 8601 or Unix timestamp).
end_time
datetime
End of time range (ISO 8601 or Unix timestamp).
app_name
string
Filter by application name (e.g., Chrome, Code).
window_name
string
Filter by window title (partial match).
browser_url
string
Filter by browser URL (partial match, works with Chrome, Safari, Firefox, Edge).
focused
boolean
Only return content from focused windows.
speaker_ids
array
Filter audio by speaker IDs (comma-separated: 0,1,2).
speaker_name
string
Filter audio by speaker name (case-insensitive partial match).
min_length
integer
Minimum content length (characters).
max_length
integer
Maximum content length (characters).
include_frames
boolean
default:"false"
Include frame image data (base64-encoded).
max_content_length
integer
Truncate content to this many characters (middle-truncation).

Advanced Queries

curl "http://localhost:3030/search?q=error&start_time=$(date -u -v-1H +%Y-%m-%dT%H:%M:%SZ)"
Time formats supported:
  • ISO 8601: 2026-03-08T14:30:00Z
  • Unix timestamp: 1709911800
  • Relative: Use JavaScript Date or shell date command
curl "http://localhost:3030/search?q=documentation&app_name=Chrome"
Common app names:
  • macOS: Chrome, Safari, Code, Finder, Terminal, Slack, Zoom
  • Windows: chrome.exe, code.exe, explorer.exe, cmd.exe
  • Linux: chrome, code, nautilus, gnome-terminal
curl "http://localhost:3030/search?q=roadmap&speaker_ids=0&content_type=audio"
Speaker IDs are assigned automatically during transcription. Use the /speakers endpoint to view and label speakers.

Search Implementation

Full-Text Search (FTS5)

screenpipe uses SQLite FTS5 (full-text search) for fast keyword matching:
-- FTS5 virtual table for OCR text
CREATE VIRTUAL TABLE ocr_text_fts USING fts5(
    ocr_text,
    content='frames',
    content_rowid='id'
);

-- Search query
SELECT * FROM ocr_text_fts 
WHERE ocr_text_fts MATCH 'meeting notes'
ORDER BY rank;
FTS5 Features:
  • Stemming: Searches running match run, runs, runner
  • Ranking: Results sorted by relevance (BM25 algorithm)
  • Phrase search: Use quotes for exact phrases: "screenpipe documentation"
  • Boolean operators: meeting AND notes, bug OR error
New event-driven frames store accessibility text directly on the frame row:
-- Accessibility text is on frames table
SELECT * FROM frames
WHERE accessibility_text LIKE '%search term%'
   OR frame_id IN (
       SELECT rowid FROM accessibility_text_fts 
       WHERE accessibility_text_fts MATCH 'search term'
   )
Thumbnail correctness: Since accessibility text is on the same row as the frame, search results always show the correct screenshot — no more desync between OCR text and thumbnails.

Search Cache

Frequent searches are cached to reduce database load:
// Compute cache key from query parameters
pub fn compute_search_cache_key(query: &SearchQuery) -> u64 {
    let mut hasher = DefaultHasher::new();
    query.q.hash(&mut hasher);
    query.pagination.limit.hash(&mut hasher);
    query.content_type.hash(&mut hasher);
    query.start_time.hash(&mut hasher);
    query.end_time.hash(&mut hasher);
    // ... hash all parameters
    hasher.finish()
}

// Check cache before querying database
let cache_key = compute_search_cache_key(&query);
if let Some(cached) = state.search_cache.get(&cache_key).await {
    return Ok(JsonResponse((*cached).clone()));
}

Search Response Format

{
  "data": [
    {
      "type": "OCR",
      "content": {
        "frame_id": 12345,
        "text": "Meeting notes from Q4 planning...",
        "timestamp": "2026-03-08T14:23:00Z",
        "file_path": "~/.screenpipe/data/2026-03-08/1709911380000_m0.jpg",
        "app_name": "Notes",
        "window_name": "Q4 Planning.txt",
        "text_source": "accessibility",
        "capture_trigger": "app_switch"
      }
    },
    {
      "type": "Audio",
      "content": {
        "chunk_id": 67890,
        "transcription": "Let's review the roadmap for next quarter.",
        "timestamp": "2026-03-08T14:25:00Z",
        "device_name": "MacBook Pro Microphone",
        "speaker_id": 0,
        "speaker_name": "John Doe"
      }
    }
  ],
  "pagination": {
    "limit": 10,
    "offset": 0,
    "total": 142
  }
}

Performance

Search Speed

  • Keyword search: 10-50ms (indexed)
  • Time range filter: +5-10ms
  • App/window filter: +5-10ms
  • Total (cached): less than 5ms
  • Total (uncached): 20-100ms
Timeout: Search queries time out after 30 seconds. If you hit this limit, narrow your time range or add more filters.

Optimization Tips

1

Use Time Filters

Always specify start_time/end_time when possible:
# Slow (searches entire database)
/search?q=meeting

# Fast (searches last 24 hours)
/search?q=meeting&start_time=2026-03-07T00:00:00Z
2

Add Content Type Filters

# Slow (searches OCR + audio)
/search?q=error

# Fast (searches OCR only)
/search?q=error&content_type=ocr
3

Avoid include_frames Unless Needed

Frame extraction adds 100-500ms per result. Only use when displaying thumbnails:
# Fast (metadata only)
/search?q=meeting&limit=100

# Slow (includes frame extraction)
/search?q=meeting&limit=100&include_frames=true

Reference

Source files:
  • Search API: crates/screenpipe-engine/src/routes/search.rs
  • Database search: crates/screenpipe-db/src/search.rs
  • FTS5 schema: crates/screenpipe-db/src/schema.sql
  • Frame extraction: crates/screenpipe-engine/src/video_utils.rs

Build docs developers (and LLMs) love