Skip to content
awall451Public

About

A facebook marketplace listing generator and dashboard.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Fleabook logo

Fleabook

Turn photos of your stuff into ready-to-paste Facebook Marketplace listings.

Drop in a few photos → Claude identifies the item, writes the listing, and researches what it actually sells for → the app lays out every Marketplace field with a copy button. You paste into Facebook by hand. There's also a dashboard with earnings graphs and a GitHub-style selling-streak heatmap.

Local-only, runs in Docker, authenticates with your own Claude subscription.

Screenshots

The listing workspace — drop in photos, get every Facebook field with a copy button, plus price research that shows its working. A bundle is itemized line by line, so the estimate is something you can check rather than a number you have to trust:

Listing detail

Your listings at a glance — every status chip carries its count, so you can see where the work is instead of clicking through empty filters. Search covers titles, brands, models and tags:

Listings grid

Or as rows, sorted by price, days listed, or title — each one expanding in place to show the estimate, the retail anchor and the renewal history:

Listings in row view

Dashboard — total earned, monthly trend, listings by status, a GitHub-style selling-streak heatmap, and what the agent spent per listing (shown with sample data):

Dashboard


Why it works this way

Facebook has no public API for person-to-person Marketplace listings. The Catalog/Commerce API only reaches Marketplace for approved partner verticals (vehicles, real estate, jobs), and browser automation against the listing form violates Meta's terms and risks your account.

So Fleabook doesn't try to post for you. Posting was never the slow part — typing the form takes thirty seconds. Deciding what to type — what the thing is, how to describe it, what it's worth — takes ten minutes. That is the part this automates. The last step is a copy-paste you do yourself, which keeps it entirely within Facebook's rules.

Features

  • Photo → listing in one click. Identify + price run as a single job; the whole thing finishes server-side even if you close the tab.
  • Real pricing research. Searches the web for used comparables, falls back to retail-minus-depreciation when comps are thin, and shows its reasoning and sources.
  • Seller-voice descriptions. Written as the owner, not a photo caption — no "appears to be", no invented flaws, no made-up backstory.
  • Context box. Tell Claude what the photos can't show ("the white one is sealed", a purchase link, "keep it short") and it feeds both identify and pricing.
  • Copy-per-field UI mirroring Facebook's form exactly, with live character counters.
  • Configurable meetup note appended to every description (set once in Settings).
  • EXIF/GPS stripped from every upload — a photo taken at home won't leak your address.
  • Dashboard: total earned, monthly earnings, listings-by-status, and a GitHub-style daily-earnings heatmap.

Quickstart

Docker (recommended)

docker compose up -d --build

Then open http://127.0.0.1:5180.

The port is bound to 127.0.0.1 on purpose — this app has no auth of its own and spends your Claude subscription on every agent run, so it should not be exposed to a network.

On the host (no Docker)

npm install
npm run dev

Windows

Windows runs the app natively — no WSL, no Docker. Download the latest release and run Fleabook-Setup.exe. It installs for you only, under %LOCALAPPDATA%, so Windows never asks for an administrator password, and it adds Start-menu and desktop shortcuts plus an entry in Settings → Apps. Fleabook then opens in its own window — not a browser tab. A portable zip is in the same release for anyone who would rather not install anything; unzip it and double-click Fleabook.exe. Note that GitHub's green Code → Download ZIP button gives you the source, not the app — the executable only comes from a release.

The window is drawn with the Microsoft Edge WebView2 Runtime, which ships with Windows 11 and is on most Windows 10 machines; the installer adds it if it is missing. Neither build is code-signed, so the first run shows SmartScreen's "Windows protected your PC" — More info → Run anyway.

Listings and photos live in %LOCALAPPDATA%\Fleabook\data, not in the program folder, so upgrading or uninstalling never touches them (the uninstaller asks separately, and defaults to keeping them).

Connect it to Claude from Settings, which handles both options without a command prompt: Sign in with Claude for a subscription (a browser page opens; paste the code it returns), or an API key in the box below it. Note that signing in to the separate Claude desktop app does not sign in Fleabook — the two keep credentials in different places, so the in-app sign-in is required even on a machine where that app is already logged in.

To build the package yourself, from Linux or Windows:

node scripts/build-windows.mjs

That produces dist-windows/Fleabook-Setup.exe, the unpacked dist-windows/Fleabook/, and a zip beside them (~160 MB compressed; most of it is the Claude Code binary the Agent SDK ships). It needs Go and makensis (apt install nsis) on the build machine, plus network access to fetch the pinned Node runtime. --no-installer skips the NSIS step. It does not touch the Docker build.

Windows Docker Desktop also works if you prefer it — docker compose up -d --build is unchanged — but set CLAUDE_DIR first, because Compose expands ${HOME} and Windows doesn't set it:

echo CLAUDE_DIR=%USERPROFILE%\.claude> .env

Authentication

Fleabook uses the Claude Agent SDK, which authenticates with the credentials the Claude Code CLI already stored — no API key needed if you're logged in with claude. Under Docker, that's why ~/.claude is bind-mounted.

Two things to understand about that mount:

  • It's read-write, and it's the whole directory. OAuth token refresh rewrites .credentials.json, and bind-mounting that single file breaks when the process replaces it via rename. So the directory is mounted, which means the container can write to your entire Claude Code config, conversation history included. If that's more access than you want, run on the host instead (npm run dev) — the SDK finds the same credentials natively.
  • It's for personal use. Anthropic does not permit third-party developers to offer claude.ai login for their products. A tool you run on your own machine for your own listings isn't that — but if you ever share or expose it, switch to an API key: set ANTHROPIC_API_KEY (uncomment it in docker-compose.yml) and the same code path uses it.

If you don't have a subscription

An Anthropic API key works instead, and can be entered in Settings rather than as an environment variable — there is no compose file to edit in the Windows build. Settings also explains where to get one. The key is stored in the app's own SQLite database in plain text, alongside the meetup note; that database is local and never leaves the machine, but it is worth knowing before you put a key in it.

src/lib/server/auth.ts resolves the three sources in order, first hit wins:

  1. ANTHROPIC_API_KEY in the environment — the operator's override. It outranks the database deliberately, so a deployment can't be repointed at someone else's billing from the web UI.
  2. A key saved in Settings.
  3. Neither — the SDK falls back to the Claude Code OAuth credentials.

That resolution happens in one place and produces one environment object. The agent code does not branch on which source won.

How a listing gets made

Two agent stages, deliberately separate, run back-to-back as one server-side job:

  1. Identify (~15s, no web access) reads the photos and fills in title, description, category, condition, and flaws. Catching a misidentification here is cheap.
  2. Price (3–5 minutes, searches the web) finds real used comparables, falls back to retail-minus-depreciation when comps are thin, and reports its basis, confidence, reasoning, and the URLs it opened.

Progress streams over SSE. The work is not tied to the browser — close the tab mid-run and the result still lands in the database. Fire a listing, move to the next, come back later.

On the price numbers

Web search reaches asking prices far more easily than completed sales (eBay's sold data is mostly behind JS and login), and asking prices run high. The agent adjusts for that, but the number is a starting point to negotiate from, not gospel — which is why the range, the reasoning, and the sources sit right next to it, and the price field stays editable.

Configuration

  • Meetup note (Settings): a line appended to every description — where/how to meet. The agent is told never to write meetup/pickup/payment language itself, so this is the single source of it.
  • Port / origin: default 127.0.0.1:5180. Behind a reverse proxy, add your hostname's origin to csrf.trustedOrigins in vite.config.ts (see the comment there) or SvelteKit's CSRF check will reject uploads.

Project layout

src/
  routes/                     SvelteKit pages + API routes
    dashboard/                earnings dashboard
    listing/[id]/             the workhorse: edit + copy fields, run the agent
  lib/
    server/
      db.ts                   sqlite via node:sqlite (no native dependency)
      images.ts               sharp: resize, thumbnail, EXIF/GPS strip
      categories.ts           curated Facebook category enum
      depreciation.ts         retention curves, passed into the pricing prompt
      dashboard.ts            earnings aggregation + sample-data seeding
      agent/
        run.ts                query() wrapper: isolation, tool locking, JSON validate + retry
        identify.ts           stage 1 prompt + schema
        price.ts              stage 2 prompt + schema
        sse.ts                progress streaming that survives client disconnect
scripts/
  smoke-agent.mjs             verifies auth + settingSources isolation
  dump-messages.mjs           prints raw Agent SDK message shapes

Tech stack

SvelteKit 2 + Svelte 5, adapter-node. SQLite via Node's built-in node:sqlite (no native build). sharp for images, zod for validating agent output, @anthropic-ai/claude-agent-sdk for the model. Charts are hand-rolled inline SVG/CSS — no charting dependency.

Gotchas worth knowing

  • settingSources: [] is load-bearing. Without it the agent inherits ~/.claude/CLAUDE.md and any globally installed skills, and writes listing copy in that voice — a stylized global skill makes descriptions sound like it instead of like a normal seller. Run node scripts/smoke-agent.mjs to confirm isolation after changing agent options or upgrading the SDK.
  • Origin handling is split across two files, and both halves matter. docker-compose.yml sets HOST_HEADER/PROTOCOL_HEADER so the origin is derived from request headers (covers a proxy); vite.config.ts also lists direct origins under csrf.trustedOrigins (covers direct port access, where PROTOCOL_HEADER is absent and adapter-node otherwise assumes https). Change the port and both files need updating.
  • BODY_SIZE_LIMIT defaults to 512K in adapter-node, which rejects a single phone photo. docker-compose.yml raises it to 128M. Nothing that large is stored — uploads are downscaled to 1600px on arrival.
  • Agent restarts orphan in-flight runs. A listing frozen at identifying/pricing after a restart is reset to a recoverable state on the next boot — no permanent zombies.
  • Progress notes depend on an undocumented SDK detail — tool calls arrive as tool_use content blocks nested inside assistant messages. If notes go quiet after an SDK upgrade, run node scripts/dump-messages.mjs <photo-dir> and check whether the shape moved.

License

MIT — see LICENSE.


Fleabook
Made for flea-market flippers. Not affiliated with Facebook or Meta.

About

A facebook marketplace listing generator and dashboard.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages