BlurShot API Documentation

Integration guide for developers building extensions and integrations with BlurShot's privacy-first screenshot editing capabilities.

Overview

BlurShot is designed as a privacy-first, client-side application. All image processing happens in the browser using HTML5 Canvas APIs. There is no backend API for processing images, as this would violate our core privacy principles.

However, BlurShot provides several integration points for browser extensions, automation tools, and other applications that want to leverage our client-side processing capabilities.

Teams that need rapid annotation before blurring often pair their flows with AnnotateFast, one of our privacy-first partners focused on screenshot markup.

JavaScript Integration

🔧 Browser Extension Integration

BlurShot can be embedded in browser extensions to provide screenshot editing capabilities directly in your extension's popup or side panel.

Creating Share Links Programmatically

JavaScript
// Share payload structure used by BlurShot
const shareState = {
  i: imageDataBase64, // image data (without the data:image/png;base64, prefix)
  n: 'screenshot.png', // optional filename
  c: 12 // optional edit count metadata
};

const encoded = btoa(JSON.stringify(shareState));
const shareUrl = `https://blurshot.io/#s=${encodeURIComponent(encoded)}`;
window.location.href = shareUrl; // or copy to clipboard
JavaScript
// Decoding a BlurShot share link
const url = new URL('https://blurshot.io/#s=eyJpIjoiUE5H...');
const payload = url.hash.slice(3); // remove '#s='
const json = atob(decodeURIComponent(payload));
const state = JSON.parse(json);
const imageDataUrl = `data:image/png;base64,${state.i}`;

// Use the data URL however you like (download, store, etc.)

Share Payload Limits

  • Max encoded image size: ~5 MB (after stripping the data:image/*;base64, prefix).
  • Max URL/hash length: ~250 KB. Browsers may truncate longer URLs.
  • If either limit is exceeded the UI surfaces a fallback alert instructing the user to download instead.

Restoring Shared Edits

To load an edit on another device, open the #s= link shown after sharing. The legacy ?edit= query only works on the same browser where the IndexedDB history was created.

// Open a share link in a new tab
const shareUrl = 'https://blurshot.io/#s=eyJpIjoiUE5H...';
window.open(shareUrl, '_blank');

// Legacy (same-device only)
window.location.href = 'https://blurshot.io/?edit=42';

URL Parameters

Parameter Description Example
#s Hash fragment containing the share payload (base64 JSON with i, n, c fields). Preferred method for cross-device restores. #s=eyJpIjoiUE5H...
edit (legacy) Loads a local IndexedDB entry by ID. Works only on the same browser profile where the history entry exists. ?edit=42

Local Storage API

BlurShot uses IndexedDB for storing edit history. Extensions and integrations can access this data to build features like "recently edited" lists or batch processing workflows.

Reading Edit History

// Access BlurShot's IndexedDB
const db = await window.indexedDB.open('BlurShotHistory', 1);

// Get all edit history
const transaction = db.transaction(['edits'], 'readonly');
const store = transaction.objectStore('edits');
const allEdits = await store.getAll();

// Each edit contains:
// {
//   id: number,
//   timestamp: number,
//   imageDataUrl: string,
//   imageName: string,
//   editCount: number,
//   thumbnail: string
// }

Browser Extension Example

Chrome Extension Manifest

{
  "manifest_version": 3,
  "name": "Screenshot Editor Extension",
  "version": "1.0",
  "permissions": ["activeTab", "storage"],
  "action": {
    "default_popup": "popup.html"
  },
  "content_security_policy": {
    "extension_pages": "script-src 'self'; object-src 'self'"
  }
}

Extension Background Script

// Capture screenshot and send to BlurShot
chrome.action.onClicked.addListener(async (tab) => {
  // Capture visible tab
  const screenshot = await chrome.tabs.captureVisibleTab(
    null,
    { format: 'png' }
  );

  // Strip the data URI prefix to get just the base64 data
  const base64Data = screenshot.split(',')[1];

  // Create share payload
  const shareState = {
    i: base64Data,
    n: 'screenshot.png',
    c: 1
  };

  // Encode and create share URL
  const encoded = btoa(JSON.stringify(shareState));
  const blurShotUrl = `https://blurshot.io/#s=${encodeURIComponent(encoded)}`;
  chrome.tabs.create({ url: blurShotUrl });
});

Framework Integration Examples

Examples showing how to integrate BlurShot's share link functionality into popular frontend frameworks.

React Component Example

import React, { useState } from 'react';

function ScreenshotEditor() {
  const [imageData, setImageData] = useState(null);

  const handleFileUpload = (e) => {
    const file = e.target.files[0];
    if (!file) return;

    const reader = new FileReader();
    reader.onload = (event) => {
      setImageData(event.target.result);
    };
    reader.readAsDataURL(file);
  };

  const openInBlurShot = () => {
    if (!imageData) return;

    // Strip the data URI prefix to get base64
    const base64Data = imageData.split(',')[1];

    // Create share payload
    const shareState = {
      i: base64Data,
      n: 'screenshot.png',
      c: 0
    };

    // Encode and create URL
    const encoded = btoa(JSON.stringify(shareState));
    const blurShotUrl = `https://blurshot.io/#s=${encodeURIComponent(encoded)}`;

    // Open in new window
    window.open(blurShotUrl, '_blank');
  };

  return (
    <div className="screenshot-editor">
      <input
        type="file"
        accept="image/*"
        onChange={handleFileUpload}
        className="file-input"
      />
      {imageData && (
        <button
          onClick={openInBlurShot}
          className="btn-primary"
        >
          Edit in BlurShot
        </button>
      )}
    </div>
  );
}

export default ScreenshotEditor;

Vue Component Example

<template>
  <div class="screenshot-editor">
    <input
      type="file"
      accept="image/*"
      @change="handleFileUpload"
      class="file-input"
    />
    <button
      v-if="imageData"
      @click="openInBlurShot"
      class="btn-primary"
    >
      Edit in BlurShot
    </button>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const imageData = ref(null);

const handleFileUpload = (event) => {
  const file = event.target.files[0];
  if (!file) return;

  const reader = new FileReader();
  reader.onload = (e) => {
    imageData.value = e.target.result;
  };
  reader.readAsDataURL(file);
};

const openInBlurShot = () => {
  if (!imageData.value) return;

  // Strip the data URI prefix to get base64
  const base64Data = imageData.value.split(',')[1];

  // Create share payload
  const shareState = {
    i: base64Data,
    n: 'screenshot.png',
    c: 0
  };

  // Encode and create URL
  const encoded = btoa(JSON.stringify(shareState));
  const blurShotUrl = `https://blurshot.io/#s=${encodeURIComponent(encoded)}`;

  // Open in new window
  window.open(blurShotUrl, '_blank');
};
</script>

<style scoped>
.screenshot-editor {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.btn-primary {
  padding: 0.5rem 1rem;
  background-color: #4f46e5;
  color: white;
  border: none;
  border-radius: 0.5rem;
  cursor: pointer;
}

.btn-primary:hover {
  background-color: #4338ca;
}
</style>

Python Automation Example

For DevOps teams automating screenshot sanitization in CI/CD pipelines or batch processing workflows.

import base64
import json
import urllib.parse
import webbrowser
from pathlib import Path

def sanitize_screenshot_with_blurshot(image_path: str, auto_open: bool = True) -> str:
    """
    Generate a BlurShot share URL for a local image file.

    Args:
        image_path: Path to the image file to sanitize
        auto_open: Whether to automatically open the URL in browser

    Returns:
        The BlurShot share URL

    Example:
        >>> sanitize_screenshot_with_blurshot('screenshot.png')
        'https://blurshot.io/#s=eyJpIjoiL...'
    """
    # Read and encode the image file
    image_file = Path(image_path)
    if not image_file.exists():
        raise FileNotFoundError(f"Image not found: {image_path}")

    # Read image as base64
    with open(image_file, 'rb') as f:
        image_data = base64.b64encode(f.read()).decode('utf-8')

    # Create share payload matching BlurShot's format
    share_state = {
        "i": image_data,              # Image data (base64)
        "n": image_file.name,         # Filename
        "c": 0                        # Edit count (0 for new)
    }

    # Encode and create share URL
    encoded = base64.b64encode(
        json.dumps(share_state).encode('utf-8')
    ).decode('utf-8')

    blurshot_url = f"https://blurshot.io/#s={urllib.parse.quote(encoded)}"

    if auto_open:
        webbrowser.open(blurshot_url)

    return blurshot_url


# Batch processing example
def batch_sanitize_screenshots(directory: str, pattern: str = "*.png"):
    """
    Process multiple screenshots in a directory.

    Example:
        >>> batch_sanitize_screenshots('./screenshots', '*.png')
    """
    screenshots_dir = Path(directory)
    results = []

    for image_file in screenshots_dir.glob(pattern):
        try:
            url = sanitize_screenshot_with_blurshot(
                str(image_file),
                auto_open=False
            )
            results.append({
                "file": image_file.name,
                "url": url,
                "status": "success"
            })
            print(f"✓ Generated URL for {image_file.name}")
        except Exception as e:
            results.append({
                "file": image_file.name,
                "error": str(e),
                "status": "failed"
            })
            print(f"✗ Failed to process {image_file.name}: {e}")

    # Save URLs to file for team distribution
    with open('blurshot_urls.json', 'w') as f:
        json.dump(results, f, indent=2)

    return results


if __name__ == "__main__":
    # Single screenshot example
    url = sanitize_screenshot_with_blurshot('bug-report-screenshot.png')
    print(f"BlurShot URL: {url}")

    # Batch processing example
    # batch_sanitize_screenshots('./support-tickets/', '*.png')

Troubleshooting Integration Issues

Common issues when integrating BlurShot and their solutions.

❌ Share URL Too Long (413 Payload Too Large)

Problem: Large images (>5MB) create URLs exceeding browser/server limits.

✓ Solution:

  • Resize images before encoding (recommended max: 1920x1080)
  • Compress to JPEG with 80-90% quality instead of PNG
  • BlurShot automatically compresses images >10MB on load
  • URL length limit: ~200KB of base64-encoded data
// Example: Compress image before sharing
const canvas = document.createElement('canvas');
canvas.width = Math.min(1920, img.width);
canvas.height = Math.min(1080, img.height);
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
const base64 = canvas.toDataURL('image/jpeg', 0.85).split(',')[1];

❌ CORS Errors When Loading External Images

Problem: Browser blocks loading images from external domains due to CORS policy.

✓ Solution:

  • Use crossOrigin="anonymous" on img elements
  • Ensure your image server sends proper CORS headers
  • Alternative: Fetch image via your backend proxy to avoid CORS
  • For local development: Use a CORS proxy or fetch via your server
// Correct way to load cross-origin images
const img = new Image();
img.crossOrigin = 'anonymous';
img.src = 'https://example.com/screenshot.png';

❌ Invalid Base64 Encoding Errors

Problem: Share URLs fail to load with "Invalid encoding" or "Failed to parse state" errors.

✓ Solution:

  • Strip the data:image/png;base64, prefix from data URLs
  • Use encodeURIComponent() on the final URL parameter
  • Ensure JSON is valid before encoding (use JSON.stringify)
  • Test with small images first to isolate encoding issues
// ❌ Wrong - includes data URI prefix
const wrong = btoa(JSON.stringify({ i: dataUrl }));

// ✓ Correct - strip prefix first
const base64Only = dataUrl.split(',')[1];
const correct = btoa(JSON.stringify({ i: base64Only, n: 'file.png', c: 0 }));

❌ Feature Not Working in Older Browsers

Problem: BlurShot requires modern browser APIs not available in IE11 or older browsers.

✓ Solution:

  • Minimum requirements: Chrome 90+, Firefox 88+, Safari 14+, Edge 90+
  • BlurShot uses Canvas API, FileReader API, and modern JavaScript (ES2020+)
  • For older browser support: Provide a fallback download link or server-side processing
  • Test using typeof FileReader !== 'undefined'

❌ Slow Performance with Large Images

Problem: BlurShot becomes slow or unresponsive when processing very large images (>10MB or >4K resolution).

✓ Solution:

  • BlurShot automatically downsamples images >4096x4096px
  • For batch processing: Process one image at a time (don't open multiple tabs)
  • Recommended max: 25MB file size, 4K resolution
  • Use Web Workers for preprocessing if integrating into your app

Privacy Considerations

⚠️ Important Privacy Note

When integrating BlurShot, ensure you respect user privacy:

  • Never send images to external servers without explicit user consent
  • Keep all processing client-side whenever possible
  • If using iframe integration, use sandbox attributes appropriately
  • Respect users' edit history privacy - don't sync or upload without permission

Support & Questions

Have questions about integrating BlurShot into your application or browser extension?

Contact Support

Related Resources

Looking for more privacy tools?TextToolboxoffers complementary features for your workflow.

BlurShot

Privacy-first screenshot editor. Blur, pixelate, and redact sensitive information directly in your browser. No uploads, no tracking, 100% free.

Privacy & Security

  • ✓ No server uploads
  • ✓ No data collection
  • ✓ No tracking cookies
  • ✓ 100% client-side processing

You might also like:TextToolbox

© 2025 BlurShot - Privacy-first screenshot editor