Self-hosted read-later service with native Kindle delivery. Save articles, send to your e-reader, keep them forever. Open-source alternative to Pocket + Send-to-Kindle. https://www.saveto.ink/
  • Go 81.1%
  • TypeScript 11.7%
  • Astro 2.8%
  • Svelte 2.6%
  • Just 1.1%
  • Other 0.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-05-14 14:19:30 +03:00
.github ci: update wrangler config 2026-05-12 11:25:05 +03:00
.justfiles feat: replace JWT with PASETO for webapp user authentication (#211) 2026-04-17 22:06:44 -04:00
backend chore: bump versions to 0.34.5 2026-05-14 14:19:30 +03:00
cli/savetoink feat(cli): add support for epub files 2026-03-23 18:21:28 -04:00
docs refactor(backend): make validation internal 2026-03-15 14:33:25 -04:00
frontend chore: bump versions to 0.34.5 2026-05-14 14:19:30 +03:00
infra ci: update node version for webapp deploy 2026-04-30 20:26:37 -04:00
tools chore(deps): bump tools 2026-04-30 20:29:00 -04:00
.dockerignore feat(webapp): add docker draft, update sentry instrumentation 2026-03-16 11:33:25 -04:00
.gitignore fix: update tests 2026-05-13 21:15:31 +03:00
.golangci.yml refactor(backend): improve processor handler testability, add tests to repository 2026-03-10 09:45:21 -04:00
AGENTS.md feat: add support for tags 2026-03-29 08:38:48 -04:00
favicon.svg tools: remove hardcoded images 2026-03-03 21:06:55 -04:00
go.mod fix(backend): bump go-trafilatura to fix <code> issue 2026-05-14 14:17:23 +03:00
go.sum fix(backend): bump go-trafilatura to fix <code> issue 2026-05-14 14:17:23 +03:00
justfile feat(backend): add scheduler 2026-03-15 14:23:53 -04:00
lefthook.yml style(webapp): make nav links as button 2026-03-20 07:58:23 -04:00
LICENSE.md Rename license file 2026-03-02 22:18:30 -04:00
README.md fix(backend): ensure sqlite folder is correct for docker 2026-03-21 11:55:08 -04:00
VERSION chore: bump versions to 0.34.5 2026-05-14 14:19:30 +03:00

Go Report Card Quality Gate Status codecov Coverage Status Api Reference

Save To Ink

Self-hosted read-later service with native e-readers delivery. Save articles in the cloud, send to your e-reader, keep them forever. Open-source alternative to Pocket + Send-to-Kindle.

DISCLAIMER: This project is under development and not affiliated with Amazon or Kindle nor Kobo or other e-readers. Use at your own risk.

Features

  • Fetch web pages (articles, blog posts, etc), strip markup with go-trafilatura and save main readable content as HTML
  • Convert content to EPUB format with go-epub for e-reader devices
  • Optionally send to reader devices like Kindle, Kobo, etc. via email backend (only MailJet supported at the moment)
  • Deploys anywhere with Docker, also as Serverless AWS applicatio. Pluggable storage backend (Sqlite/DynamoDB)
  • Run as self-hosted web application (Web Frontend + API server) or as standalone CLI tool
  • Browser extension (Chrome, Firefox)to easy save/send pages
  • REST APIs for programmatic access

CLI Tool

The CLI tool allows you to convert web articles to EPUB format and send them to your reader device directly from the terminal.

Docker

You can run the CLI tool using Docker:

alias savetoink="docker run --rm ghcr.io/savetoink/savetoink-cli:latest"
savetoink version

Frontend and API server are also available as a Docker image:

# HTTP server
docker run --rm --env-file .env -p 8080:8080 -v $(pwd)/data:/app/data ghcr.io/savetoink/savetoink-http:latest

# Web frontend
docker run --rm --env-file .env -p 3000:3000 ghcr.io/savetoink/savetoink-webapp:latest

Note: When using SQLite as storage backend, you must mount a volume at /app/data to persist the database between container restarts. The example above mounts a data directory from your current working directory.

You can customize the database location using the SAVETOINK_SQLITE_PATH environment variable (default: savetoink.db in the container's working directory).

Installation

You can build and install the CLI tool using Go:

go install github.com/shaftoe/savetoink/cli/savetoink@latest

Or build locally using Just:

just build-cli

Usage

Send directly to Kindle via email (requires MailJet credentials as environment variables):

savetoink send https://example.com --dest-email my-kindle@kindle.com

Convert a URL to EPUB (save locally):

savetoink convert https://example.com

Specify an output file:

savetoink convert https://example.com -o my-book.epub

Examples

Save to local file:

$ savetoink convert https://golang.org/doc/effective_go.html -o effective_go.epub
✓ EPUB saved to: effective_go.epub

Send to Kindle via email:

$ savetoink send https://golang.org/doc/effective_go.html --dest-email my-kindle@kindle.com
✓ Article sent to e-reader device at my-kindle@kindle.com (email ID: fbbaf039-887a-4c86-9a8a-759562592599)"

Development

Conventions

  • this project follows the Conventional Commits convention (or at least tries to)
  • before releasing (pushing to GitHub master branch), bump the version using just bump-version

Prerequisites

  1. Install Just command runner
  2. Set required environment variables in .env (see backend/lib/config/config.go for details)
  3. Install AWS CLI and configure credentials (optional, only for AWS Lambda deployment)

Frontend

  • SSR SvelteKit app, running as CloudFlare worker or self hosted
  • WXT browser extension

To develop the frontend app locally:

just webapp

To develop the extension locally

just extension
# or
just extension-firefox

Backend

  • generic Go HTTP server with AWS DynamoDB backend
  • or deployed as AWS Lambda Function (with HTTP adapter + CloudFront for custom domain
  • pluggable database backend (DynamoDB or SQLite)
  • pluggable user backend
    • single-user shared API key
    • multi-user with Auth0
  • pluggable send email backend

Deployment

To run locally:

just http

To deploy to AWS Lambda:

# Full AWS Lambda deployment
just deploy

# Destroy AWS Lambda infrastructure
just destroy

License

See LICENSE file for details.