All guides

Move from another app

Bring your bookmarks, notes and images over from Raindrop, Pocket, your browser, Notion, Eagle, Apple Notes, Readwise or mymind.

Easiest
An AI prompt, then Import
Free plan
Up to 50 captures
On
Mac

The easy way: let an AI convert it

For bookmarks and saved links from any app, let ChatGPT, Claude or another AI assistant turn the app's export into a file Resurf imports. It keeps titles, notes, tags, favorites and the original dates, and you don't install anything.

Prompt
Turn the export file I've attached into a CSV that the Resurf app can import. If you can create files, give me a file called captures.csv. Otherwise reply with only the CSV in one code block.

Follow these rules exactly:

1. The first line is exactly:
type,title,source_url,description,user_note,tags,spaces,created_at,pinned_at
2. Write one row for every saved item that has a web address starting with http:// or https://. Skip folders, separators, bookmarklets and items without a web address, and tell me after the CSV how many you skipped.
3. type: always link, in lower case.
4. title: the item's title or name. Empty if it has none.
5. source_url: the item's full web address, exactly as in the file.
6. description: the excerpt or summary the app saved for the item. Empty if none.
7. user_note: my own note or comment on the item, including any highlights. Empty if none.
8. tags: the item's tags plus the name of the folder, collection or board it was in, separated by semicolons (;) with no spaces around them, for example design;inspiration;Travel. Don't add generic folders like "Bookmarks bar", "Unsorted" or "Other bookmarks". Empty if none.
9. spaces: leave empty.
10. created_at: when the item was saved, in UTC, as YYYY-MM-DDTHH:MM:SSZ, for example 2024-03-01T09:30:00Z. Convert Unix timestamps (seconds, milliseconds or microseconds) and written dates. If only the day is known, use T00:00:00Z. If no date is known, leave it empty.
11. pinned_at: if the item was a favorite, starred or pinned, copy its created_at here. Otherwise empty.
12. Separate columns with commas. Wrap any value that contains a comma, a double quote or a line break in double quotes, and write each double quote inside it twice.
13. Keep every item and keep the original words. Don't invent, translate or shorten anything.

If there are more than 500 items, split the CSV into parts of 500 rows, each starting with the same first line, and give me one part at a time.
  1. Export your bookmarks from the other app as a file, in any format it offers.

  2. Open ChatGPT, Claude or another assistant, attach the export, and paste the prompt above.

  3. Save what it gives you as captures.csv, or download the file it makes.

  4. In Resurf, open Settings → Data and click Import… beside Import from CSV…, pick captures.csv and click Preview.

  5. Check that Rows matches the number of items, then click Import.

For more than 500 items, the assistant gives you parts; import each part once, one after another. Rows from another app are new every time, so import each file only once.

Notes and files don't fit in this file: drag them in as a folder instead.

Other routes

Each way in keeps different things.

RouteKeepsGood for
CSV importTitles, tags, spaces, Notes and the original dates. Doesn't skip links you already saved.Raindrop, Pocket, browser bookmarks
Drag a folderImages, PDFs, video, audio, Markdown and text files, and .webloc links, one capture each. Folder names, tags and dates stay behind.Notion, Eagle, Apple Notes, any folder of files
Paste links (⌘V)One link per line. Skips links you already have. Titles and covers are fetched; tags and dates aren't kept.A quick list
The resurf commandLinks, notes, quotes and files from a script. Skips links you already have.Readwise, anything you can script

In the app, the free plan stops at 50 captures, whether you import, drag or paste. A CSV import that would pass the limit adds nothing. Spaces stop at 4.

Running a script

The CSV recipes below use a short Python script that turns another app's export into a captures.csv Resurf reads. Save the script in a folder, open Terminal in that folder, and run it with your export file:

Terminal
python3 raindrop-to-resurf.py ~/Downloads/export.csv

It writes captures.csv next to the script. Import that from Settings → Data.

The first time you run python3, macOS may offer to install its command line developer tools. Click Install, then run the command again.

Raindrop

Export your bookmarks from Raindrop as CSV and use the AI prompt above, or run this script on it and import captures.csv.

Raindrop columnBecomes
titletitle
urlsource_url
excerptdescription
noteuser_note, your Note
tagstags, commas changed to semicolons
folderspaces
createdcreated_at
favorite truepinned_at, so it's pinned
raindrop-to-resurf.pyDownload
import csv, sys
from datetime import datetime, timezone

def iso(value):
    if not value:
        return ""
    when = datetime.fromisoformat(value.replace("Z", "+00:00"))
    return when.astimezone(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")

columns = ["type", "title", "source_url", "description", "user_note", "tags", "spaces", "created_at", "pinned_at"]
with open(sys.argv[1], newline="", encoding="utf-8-sig") as source, \
     open("captures.csv", "w", newline="", encoding="utf-8") as target:
    writer = csv.DictWriter(target, fieldnames=columns)
    writer.writeheader()
    for row in csv.DictReader(source):
        created = iso(row.get("created", ""))
        tags = [tag.strip() for tag in row.get("tags", "").split(",") if tag.strip()]
        writer.writerow({
            "type": "link",
            "title": row.get("title", ""),
            "source_url": row.get("url", ""),
            "description": row.get("excerpt", ""),
            "user_note": row.get("note", ""),
            "tags": ";".join(tags),
            "spaces": row.get("folder", ""),
            "created_at": created,
            "pinned_at": created if row.get("favorite") == "true" else "",
        })

Covers and highlights stay behind; Resurf fetches its own cover for each link. On the free plan only 4 spaces can exist, so delete the spaces column first if you have more collections.

Pocket

Pocket closed in 2025, but if you downloaded your export, it holds one or more CSV files with title, url, time_added, tags and status. Use the AI prompt above on each file, or run this script on it and import captures.csv.

  • time_added is a Unix timestamp. The script turns it into a date.
  • Pocket separates tags with |. The script changes them to semicolons.
  • Read and unread status stays behind.
pocket-to-resurf.pyDownload
import csv, sys
from datetime import datetime, timezone

columns = ["type", "title", "source_url", "tags", "created_at"]
with open(sys.argv[1], newline="", encoding="utf-8-sig") as source, \
     open("captures.csv", "w", newline="", encoding="utf-8") as target:
    writer = csv.DictWriter(target, fieldnames=columns)
    writer.writeheader()
    for row in csv.DictReader(source):
        added = row.get("time_added", "")
        created = datetime.fromtimestamp(int(added), timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") if added else ""
        tags = [tag.strip() for tag in row.get("tags", "").split("|") if tag.strip()]
        writer.writerow({
            "type": "link",
            "title": row.get("title", ""),
            "source_url": row.get("url", ""),
            "tags": ";".join(tags),
            "created_at": created,
        })

Browser bookmarks

Resurf doesn't read a bookmarks file directly. For a handful, drag them from your browser's bookmarks bar or bookmarks manager onto Resurf; each becomes a link. For all of them, export your bookmarks as an HTML file and use the AI prompt above, or turn it into a CSV with this script.

  • Chrome: open the bookmarks manager, click the ⋮ menu and choose Export bookmarks.
  • Safari: choose File → Export → Bookmarks.
  • Firefox: open the Library, then Import and Backup → Export Bookmarks to HTML.
bookmarks-to-resurf.pyDownload
import csv, sys
from datetime import datetime, timezone
from html.parser import HTMLParser

class Bookmarks(HTMLParser):
    def __init__(self):
        super().__init__()
        self.folders, self.pending, self.rows, self.link, self.text = [], None, [], None, ""

    def handle_starttag(self, tag, attrs):
        attrs = dict(attrs)
        if tag == "dl":
            self.folders.append(self.pending or "")
            self.pending = None
        elif tag in ("a", "h3"):
            self.link = attrs if tag == "a" else None
            self.text = ""

    def handle_data(self, data):
        self.text += data

    def handle_endtag(self, tag):
        if tag == "h3":
            self.pending = self.text.strip()
        elif tag == "dl" and self.folders:
            self.folders.pop()
        elif tag == "a" and self.link and self.link.get("href", "").startswith("http"):
            added = self.link.get("add_date", "")
            created = datetime.fromtimestamp(int(added[:10]), timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") if added.isdigit() else ""
            folders = [name for name in self.folders if name]
            self.rows.append({"type": "link", "title": self.text.strip(), "source_url": self.link["href"],
                              "tags": ";".join(folders), "created_at": created})
            self.link = None

parser = Bookmarks()
with open(sys.argv[1], encoding="utf-8") as source:
    parser.feed(source.read())
with open("captures.csv", "w", newline="", encoding="utf-8") as target:
    writer = csv.DictWriter(target, fieldnames=["type", "title", "source_url", "tags", "created_at"])
    writer.writeheader()
    writer.writerows(parser.rows)
print(f"{len(parser.rows)} bookmarks written to captures.csv")

The script keeps each bookmark's title, address and the date you added it, and turns the folders it sits in into tags. Bookmarklets and other addresses that don't start with http are skipped.

Notion

In Notion, export the pages you want as Markdown & CSV, with subpages included, and unzip the file. Drag the folder onto Resurf. Each page becomes a note, and each image in the folder becomes its own image capture.

Database tables are CSV files, which Resurf skips; the receipt says how many files it skipped. Images inside a page don't show in its note, because they're separate files.

Eagle and Pinterest

  • Eagle: export the images you want to a folder and drag the folder onto Resurf. Each image becomes a capture. Eagle's tags, folders and notes stay behind.
  • Pinterest: there's no download of your pins' images. Drag the images you want from a board onto Resurf, or copy the pins' addresses, one per line, and paste the list with ⌘V to save them as links.

Apple Notes

  • For a few notes, select a note's text, copy it, and press ⌘V in Resurf's main window: it's saved as a note.
  • To keep a note's layout and images, choose File → Export as PDF in Notes and drag the PDF onto Resurf.
  • For many notes, use a Markdown exporter for Apple Notes, then drag the folder it makes onto Resurf.

Readwise

There are two ways.

  • One note per book: export from Readwise as Markdown, unzip it, and drag the folder onto Resurf.
  • One quote per highlight, if you use the command line: export from Readwise as CSV, run the script, and send what it writes to Resurf with the resurf command. Each highlight becomes a quote, attributed to its author and book, with its tags and your note on it.
readwise-to-resurf.pyDownload
import csv, json, sys

with open(sys.argv[1], newline="", encoding="utf-8-sig") as source:
    rows = [row for row in csv.DictReader(source) if row.get("Highlight", "").strip()]

items = []
for number, row in enumerate(rows, start=1):
    author, book = row.get("Book Author", "").strip(), row.get("Book Title", "").strip()
    item = {
        "id": str(number),
        "intent": "quote",
        "content": {"kind": "text", "text": row["Highlight"].strip()},
        "metadata": {"quoteAttribution": ", ".join(part for part in (author, book) if part)},
        "organization": {"tags": [tag.strip() for tag in row.get("Tags", "").split(",") if tag.strip()]},
    }
    if row.get("Note", "").strip():
        item["organization"]["userNote"] = row["Note"].strip()
    items.append(item)

for start in range(0, len(items), 100):
    page = start // 100 + 1
    with open(f"readwise-{page}.json", "w", encoding="utf-8") as target:
        json.dump({"requestID": f"readwise-import-{page}", "items": items[start:start + 100]}, target, ensure_ascii=False)
    print(f"readwise-{page}.json")
Terminal
python3 readwise-to-resurf.py ~/Downloads/readwise-data.csv
for request in readwise-*.json; do
  resurf capture submit --request "$request" --json | jq -c '.data.counts'
done

The script writes files of up to 100 highlights each. Running the loop again with the same files adds nothing. If you export again later, change readwise-import in the script to a new name first.

mymind

  • Look at what mymind's export gives you first.
  • A folder of images, PDFs or notes: drag it onto Resurf.
  • A list of links in any format: use the AI prompt above.

Questions

Will my old dates come with me?

Through a CSV import, yes, from the created_at column. Dragged files and pasted links are dated when you add them.

Can I import the same export twice?

Not by CSV: rows from other apps are added again each time. Pasting links or saving them with the resurf command skips links you already have.

How many can I bring over on the free plan?

In the app, up to 50 captures and 4 spaces in all. A CSV import that would pass 50 stops before it adds anything, so you can activate a license first and run it again.