Skip to main content

Endpoint

POST /api/extension/import
Bulk imports bookmarks from browser exports or other sources. Handles deduplication, validation, and batched inserts.

Authentication

Requires authentication via session cookie.

Headers

Request Body

Response

success
boolean
required
Always true on success
groupId
string
required
ID of the group where bookmarks were imported
groupName
string
required
Name of the import group (“Imported - Browser”)
importedCount
number
required
Number of bookmarks successfully imported
skippedCount
number
required
Number of bookmarks skipped (duplicates or errors)
truncated
boolean
required
Whether the input was truncated due to exceeding the 2,000 limit
limit
number
required
Maximum number of bookmarks allowed (2,000)
errorSummary
object
Optional breakdown of errors encountered
errorSummary.invalidUrl
number
Number of bookmarks with invalid URLs
errorSummary.duplicateInBatch
number
Number of duplicate URLs within the import batch
errorSummary.duplicateInGroup
number
Number of URLs already in the import group
errorSummary.chunkInsertFailed
number
Number of bookmarks that failed to insert

Example

const response = await fetch('https://minimal.to/api/extension/import', {
  method: 'POST',
  credentials: 'include',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    bookmarks: [
      { title: 'Example Site', url: 'https://example.com' },
      { title: 'GitHub', url: 'https://github.com' },
      { title: 'Stack Overflow', url: 'https://stackoverflow.com' },
      // ... up to 2,000 bookmarks
    ]
  })
});

const data = await response.json();
console.log(data);
// {
//   success: true,
//   groupId: "grp_123",
//   groupName: "Imported - Browser",
//   importedCount: 3,
//   skippedCount: 0,
//   truncated: false,
//   limit: 2000
// }

Behavior

Import Limits

  • Maximum 2,000 bookmarks per request
  • Requests exceeding 2,000 bookmarks are truncated
  • Bookmarks are inserted in chunks of 500 for performance

Destination Group

All imported bookmarks go to a group named “Imported - Browser”:
  • Created automatically if it doesn’t exist
  • Uses color #6366f1
  • Reused for subsequent imports

Deduplication

Within the import batch:
  • URLs are normalized before comparison
  • Duplicate URLs in the same batch are skipped
  • Only the first occurrence is imported
Against existing bookmarks:
  • URLs already in the “Imported - Browser” group are skipped
  • No cross-group duplicate detection

URL Validation

URLs are validated and normalized:
  • Must be valid HTTP or HTTPS URLs
  • Non-HTTP(S) protocols are rejected
  • Invalid URLs are counted in errorSummary.invalidUrl

Error Handling

  • Individual bookmark failures don’t abort the entire import
  • Chunk insert failures are logged and counted
  • The response includes a detailed error summary

Schema

const importBookmarkSchema = z.object({
  title: z.string(),
  url: z.string(),
});

const importRequestSchema = z.object({
  bookmarks: z.array(importBookmarkSchema),
});

Error Responses

// 401 Unauthorized
{
  "error": "Unauthorized",
  "message": "Please log in to import bookmarks"
}

// 400 Bad Request
{
  "error": "Bad Request",
  "message": "Invalid payload. Expected { bookmarks: Array<{ title, url }> }"
}

// 403 Forbidden
{
  "error": "Forbidden",
  "message": "Origin not allowed"
}

// 500 Server Error
{
  "error": "Server Error",
  "message": "Failed to import bookmarks"
}

Performance

  • Batched inserts (500 bookmarks per chunk) for optimal database performance
  • Single query to fetch existing bookmarks in the group
  • URL normalization uses in-memory Set for O(1) deduplication
  • Average import time logged for monitoring

Use Cases

  • Import bookmarks from browser HTML export
  • Migrate from another bookmark service
  • Bulk add URLs from a reading list
  • Restore bookmarks from backup

Constants

const IMPORT_LIMIT = 2000;        // Max bookmarks per request
const CHUNK_SIZE = 500;           // Bookmarks per database insert
const IMPORTED_GROUP_NAME = "Imported - Browser";
const IMPORTED_GROUP_COLOR = "#6366f1";

Source

  • Implementation: app/api/extension/import/route.ts:33
  • Schema: route.ts:18-25