Privacy and security - dvnkln/hdtracker GitHub Wiki
What hdtracker sends where, what stays on your server, and how your data is stored.
In short
- Your library, your progress and your account live in one database file on your server. hdtracker has no cloud, no accounts at a third party, no statistics and no tracking.
- To show titles, posters and release dates, hdtracker asks public databases (TMDB, IGDB, AniList, Wikidata). They learn which titles are looked up β never who you are in hdtracker, what status you gave a title or what you have watched.
- Your browser only ever talks to your own hdtracker. Posters and other images are fetched by the server and passed on.
- Nothing else is contacted: no update check, no fonts or scripts from other servers.
- Several people can share one installation. Each has a library of their own that nobody else sees, apart from titles two people choose to track together β see Several accounts.
- The one exception you can switch on yourself: notifications.
- To your own devices they travel through the push service of your browser's maker, which cannot read them.
- If you add Pushover, ntfy or a webhook as a target, that service receives them in readable form.
Who the server talks to
These are all outgoing connections of the hdtracker server. Each one uses HTTPS.
| Address | Used for | What is sent |
|---|---|---|
api.themoviedb.org |
Movies and series: search, details, episodes, release dates, where to watch. Anime: episode titles and where to watch (see below) | Search text or the ID of a title, your content language, your TMDB token |
id.twitch.tv |
Signing in to IGDB (IGDB belongs to Twitch) | Your IGDB client ID and secret |
api.igdb.com |
Games: search, details, release dates | Search text or the ID of a title, your IGDB client ID and a sign-in token |
graphql.anilist.co |
Anime: search, details, episodes, release dates | Search text or the ID of a title (no key, no account) |
www.wikidata.org, query.wikidata.org |
Direct links to a title on Netflix, Disney+, Prime Video and Apple TV (detail page of movies, series and anime). Asked at most once a month per title, and only for titles with streaming offers | The Wikidata ID of the title (in the background: the IDs of up to 100 titles in one request) |
github.com, release-assets.githubusercontent.com |
The list that says which TMDB season belongs to an anime (anibridge-mappings, a community project, MIT licence). The whole list is downloaded at most once a week | Nothing about you or your library β it is a plain file download, the same for everyone |
image.tmdb.org, images.igdb.com, s4.anilist.co |
Posters, episode images, backdrops and logos of streaming services | Which image is requested β nothing else, no key |
When this happens:
- When you search β your search text goes to the database of that area.
- When you open the page of a title that is not in your library β the ID of that title. Pages of titles in your library come from your own server.
- After an import β the IDs of the imported titles, to load posters, descriptions and dates.
- Every night (task Refresh metadata, Settings β Maintenance) β the IDs of the titles in your library, to keep their details, release dates and images up to date, so their pages open without waiting.
- Not every title is asked for every night: watched movies and anime and completed games once a week, dropped titles once a month, everything else nightly.
- Hidden areas are skipped.
- You can change the schedule or switch the task off.
- Right after you add or import a title β the same for that title.
hdtracker asks sparingly: one request per title and service, one after the other with a short pause, and it waits when a service asks to slow down.
The API keys in your .env file are your own. They are only sent to the service they belong to.
Notifications
Off by default. If you switch them on (Settings β Notifications), hdtracker tells you when something from your library is released. Where the messages go is up to you β see Notifications.
- A message contains the name of the title and what is released (for example the episode), or the list of the day.
- Messages about tracking together contain the name of the title and the display name of the other person. They are sent while their switches are on, also when messages about releases are off.
- Nothing is sent while there is no target or notifications are off.
- Removing a target ends it. If you never add a target, none of the services below is ever contacted.
Who can read the content of a message depends on the target:
| Target | Where the message goes | Who can read the content |
|---|---|---|
| Your own devices | The push service of your browser's maker | Only your server and your device |
| Pushover | api.pushover.net |
Pushover |
| ntfy, public service ntfy.sh | ntfy.sh |
ntfy.sh, and anyone who knows the name of your topic. According to ntfy's privacy policy, messages βmay be transmitted through Google's FCM infrastructureβ |
| ntfy, a server of your own | The server you entered | That server β and anyone who can reach it and knows the topic, unless it is protected |
| Webhook | The address you entered | Whoever runs that address |
What this page covers
- What hdtracker sends and what it stores β you can check both in the source code.
- What a service does with a message afterwards (how long it keeps it, whom it passes it on to) is described by the service itself. Each section links to its privacy information.
Your own devices
Push messages straight from the app, without any extra app or account.
How it works
- Your browser registers with the push service of its maker and gives hdtracker an address there.
- To notify you, your server sends the message to that address.
- The push service passes it on to your device.
| Browser | Push service |
|---|---|
| Chrome and most Android browsers | Google, fcm.googleapis.com |
| Firefox | Mozilla, updates.push.services.mozilla.com |
| Safari, installed apps on iPhone and iPad | Apple, web.push.apple.com |
| Edge on Windows | Microsoft, *.notify.windows.com |
hdtracker only accepts addresses at these services. The list is fixed in the app.
What the push service cannot see
- The content. hdtracker encrypts it with keys that only your browser has. The standard for this (RFC 8291) is built so that the push service can pass a message on but can neither read nor change it.
What the push service does learn
- That your server sent a message to that device, when, and how large it was.
- That the message is to be delivered right away, and that it may be dropped if the device cannot be reached for a day.
- The public key of your installation β the same for all your devices.
- A contact address. For every installation this is the project page
https://github.com/dvnkln/hdtracker, not the address of your server.
The picture
- The large picture of a notification (the poster of the title, or several posters side by side) is loaded by your device from your hdtracker, not from the push service.
- A notification appears without the app being open. Such a picture therefore has an address with a signature, which opens exactly this one picture without a login.
- Addresses of combined pictures stop working after a week.
- A message about tracking together shows the profile photo of the other person, if they uploaded one. It is loaded the same way: from your hdtracker, through a signed address that opens this one photo for a week.
Stored in hdtracker
- Your devices, with their name, their address at the push service and the two keys that encrypt messages for them, in the database.
- Removing a device in the settings, or switching notifications off in the browser, ends it. A device the push service no longer knows is removed automatically.
Pushover
Address: api.pushover.net
What hdtracker sends
- Title, text and a link to your hdtracker (the link contains the address of your hdtracker)
- The picture, if Attach the picture is on
- Your application token and your user key β also once when you save the target, to check them
- The names of your devices, if you limited the target to some of them
Nothing of it is encrypted beyond the HTTPS connection: that protects it on the way, not from Pushover. Pushover can read all of it.
Stored in hdtracker
- Token, user key, your choice of devices, the device names Pushover reported and whether the picture is attached, in the database.
- Token and user key are never shown again in the app.
What Pushover does with a message is described by Pushover: Are messages/notifications encrypted? Β· Notification storage and delivery
ntfy
Address: ntfy.sh, or the server you entered
What hdtracker sends
- Title and text, to the topic you entered
- A link to your hdtracker and the address of the icon (both contain the address of your hdtracker, unless you entered another icon address)
- The picture, if Attach the picture is on
- Your access token, if you entered one
Nothing of it is encrypted beyond the connection β and the connection only if the server address starts with https://. That protects it on the way, not from the server. The server can read all of it.
The icon itself is not sent. The ntfy app loads it from the address in the message: your hdtracker, or the icon address you entered.
A topic is not a password-protected inbox. On ntfy.sh, and on a server of your own without access rules, whoever knows or guesses the name of your topic can read your messages and send you some (ntfy: Access control). Pick a long name nobody can guess.
Stored in hdtracker
- Server, topic, icon address, the access token and whether the picture is attached, in the database.
- The access token is never shown again in the app.
What ntfy.sh does with a message is described by ntfy: Privacy policy. With a server of your own it is your configuration: ntfy documentation.
Webhook
Address: the one you entered
What hdtracker sends
- Exactly the content you wrote, with the placeholders filled in.
{{url}}and{{image}}contain the address of your hdtracker. - The header, if you set one
It goes to that address and nowhere else; redirects are not followed. Whether it is encrypted on the way depends on the address (https:// or http://).
Stored in hdtracker
- Address, content and header, in the database.
- The header is never shown again in the app.
What the receiving service does with the message, and whether it passes it on, is up to that service. Apprise, for example, forwards it to every service you configured there.
What your browser loads
Nothing from other servers. Pages, scripts, styles, fonts, icons and all images come from your own hdtracker.
Posters and other images are fetched by the server from the image servers listed above the first time they are needed, stored in /data/images and passed on to your browser. The image servers therefore only see your server, never the devices you use hdtracker on.
How long a copy is kept follows the rules of the data sources (TMDB allows six months at most):
- A copy is loaded again after about five months, and never used beyond that limit.
- Posters of the titles in your library are kept ready by the nightly refresh. A new poster is picked up the same night.
- Other images (search results, similar titles, episode images) are deleted when nobody needed them for 30 days, and simply loaded again the next time.
- The task Clean up images (Settings β Maintenance) does this. It cannot be switched off.
hdtracker also tells the browser to refuse anything from elsewhere β images, scripts, fonts, connections β so this cannot change by accident (up to version 0.5.0 this covered images only). Other websites cannot embed hdtracker in a frame either.
Links to other websites (TMDB, JustWatch, a streaming service, GitHub) are only opened when you click them, and without telling the other site where you came from.
The same goes for trailers (from version 0.9.0): a trailer is a plain link to the video site (YouTube, for some anime Dailymotion). No player is embedded, so nothing is loaded from there before you tap the link.
An app that is left open asks your own server now and then whether it was updated, to load the new version. That is not an update check with anybody else.
What never leaves your server
- Your username and password
- The status of a title (planned, watching, completed, β¦) and when you changed it
- Which episodes you have watched
- Your settings
- Any kind of usage statistics, error reports or "phone home" β hdtracker has none
What the services can see
To be clear about the limits: the databases see your server's IP address and what it asks for.
- They see your search texts and the titles you open (including which images are loaded for them).
- Because of the nightly refresh, they could work out which titles are in your library β but not your status, your progress or your account.
- TMDB and IGDB can link these requests to the API key you registered with them. AniList and Wikidata are used without a key.
- Anime and TMDB: AniList has no episode titles and no streaming offers per region, so hdtracker asks TMDB for the show an anime belongs to. TMDB therefore also sees which anime you look at or have in your library.
- If you do not want that, switch off Episode titles for anime under Settings β Server. hdtracker then neither downloads the list from GitHub nor asks TMDB about anime.
If that matters to you, you can switch off the nightly refresh; release dates on the dashboard are then only updated when you run the task yourself.
Several accounts
From version 0.8.0 an admin can add accounts for others (Users). What they see of each other:
| Who | Sees of you |
|---|---|
| Other users | Your display name (or your username while you have not set one) and your profile picture β nothing else |
| Somebody you invite to a title | Also that you track this title, and your status of it |
| Those you track a title together with | Also the status and the watched episodes of that title, which you share from then on β nothing about your other titles |
| Admins | In the app: also your username, your role, when you last logged in and how many titles you track β not which titles, your statuses or your watched episodes. Through a backup: everything (see below) |
- Admins can lock or delete an account and give it a new temporary password. They cannot read a password.
- Admins can download backups, and a backup holds the whole database: every library and the notification targets of everybody, with their keys. The app does not show an admin your titles, but it cannot stop them from opening a backup. Only make people admin you would trust with that.
- An admin could also give your account a new password and log in as you. You would notice: your own password stops working, and you are logged out everywhere.
- Deleting an account deletes its library, settings and notification targets. Titles it tracked together with others stay with them.
- Whoever stops tracking a title together takes a copy along; from then on the others no longer see what you do with it. See Users β Tracking together.
- Whoever has access to the server itself (the database file, a backup) can read everything of everybody β the database is not encrypted, see below.
- Towards the data sources nothing changes: they see one server, not who of you asked.
How your data is stored
On your server
| What | Where and how |
|---|---|
| Database | One SQLite file, /data/hdtracker.db, inside the Docker volume. It is not encrypted β anyone with access to the server or the volume can read your library. The same goes for backups in /data/backups and for backup files you download. |
| Password | Only as a salted hash (scrypt), never in plain text. If you forget it, it cannot be read out, only reset. |
| Profile pictures | Inside the database, as a small square picture. An uploaded photo is saved anew; nothing else of the original file (location, camera data) is kept. |
| Invitations and inbox | Inside the database: open invitations (who invited whom to which title) until they are answered or withdrawn, and the entries of your inbox. Entries you have read are deleted after a week. From version 0.9.0. |
| Images | Copies of posters and other images in /data/images. They contain nothing personal and can be deleted at any time. |
| Secrets | SECRET and your API keys are in the .env file on your server. Keep that file private. |
In your browser
| What | Details |
|---|---|
| Login cookie | A random token, valid for 30 days and renewed while you use the app. Scripts cannot read it. |
| Theme cookie | The name of the theme last used on this device, so the login page can show it. |
| Language cookie | The interface language last used on this device (de or en), for the same reason. From version 0.8.0. |
| Last search area | Which area you searched in last. |
| App files | When installed as an app: a copy of the app's own files (not your data), to start faster. |
Protection of your login
- Stolen database: the database only keeps a fingerprint of the login token, so a stolen database or backup does not let anyone log in as you.
- Other devices: Log out other devices (Settings β Account) ends all other logins.
- Temporary passwords: a password set by an admin or by the reset command has to be replaced right after logging in.
- Calls into your network: webhook and ntfy targets make the server call an address of the user's choice. Only admins may add them, unless an admin allows it for everybody.
- Wrong passwords: after 5 wrong passwords, logins from that address are blocked for a minute, after the next 5 for five minutes, then for 15 minutes each time.
- Behind a reverse proxy: confirm the proxy under Settings β Server so hdtracker can tell visitors apart β see HTTPS and installing as an app. A key created for that is stored in the database and only shown to the admin.
- Forms are only accepted from the address(es) you set as
ORIGIN, so another website cannot change your library behind your back.
The log
Every wrong password and every block is written to the container log with the address it came from β never the password or the user name that was typed:
Login failed: wrong password from 203.0.113.7
Login blocked: 203.0.113.7 for 5 min after 5 wrong passwords
Tools like fail2ban can read these lines; docker logs hdtracker shows them.
Use HTTPS
Also inside your home network. Over plain http://, your password and login cookie travel unencrypted, and anyone on the same network (other devices, guests, a compromised gadget) could read them.
hdtracker itself speaks plain HTTP, so put a reverse proxy in front of it. Common self-hosted ones:
- Nginx Proxy Manager β set up in the browser, good for beginners
- Caddy β a short config file, certificates are handled automatically
- Traefik β configured through Docker labels
How to connect hdtracker to a proxy: HTTPS and installing as an app.
Firewall / allow list
If you restrict outgoing connections, these are the addresses the hdtracker server needs, all on port 443. Your browser only needs to reach your hdtracker.
| Address | Needed for | From version |
|---|---|---|
api.themoviedb.org |
Movies and series; episode titles of anime | |
id.twitch.tv, api.igdb.com |
Games | |
graphql.anilist.co |
Anime | |
image.tmdb.org, images.igdb.com, s4.anilist.co |
Posters and other images | 0.4.0 (before that the browser loaded them itself) |
www.wikidata.org |
Direct links to streaming services | |
query.wikidata.org |
The same for many titles at once. Without it, the links are looked up one by one at www.wikidata.org |
0.6.0 |
github.com, release-assets.githubusercontent.com |
Episode titles of anime. Without them everything else keeps working | 0.6.0 |
fcm.googleapis.com, updates.push.services.mozilla.com, web.push.apple.com, *.notify.windows.com |
Notifications to your own devices β only if switched on | 0.7.0 |
api.pushover.net |
Only if you add a Pushover target | 0.7.0 |
ntfy.sh, or your own ntfy server |
Only if you add an ntfy target | 0.7.0 |
| The addresses of your webhooks | Only if you add a webhook target | 0.7.0 |
What happens when something is blocked:
- Your library, statuses and watched episodes keep working.
- Search, detail pages and the refresh of release dates stop working for the blocked service.
- Blocked image servers only mean missing posters.
Check it yourself
hdtracker is open source.
- Requests to the databases:
src/lib/server/providers - Images:
src/lib/server/images.ts - Notifications:
src/lib/server/push.tsandsrc/lib/server/channels - In your browser, the network tab of the developer tools shows what is loaded from where.