This page describes what the running code does, not what a template says. The tables, limits and durations below are read from the modules that apply them, so a change to the software changes this page.
Who is responsible
Stefan Seyfang, c/o Maximilian Korzekwa, Im Bruckenwasen 8, 73207 Plochingen, Germany, is the controller within the meaning of Article 4(7) GDPR. Contact: German.saas@web.de. Full details: imprint.
Reading this site without an account
You can read every public page without an account and without identifying yourself. What happens then:
- One cookie is set:
tdp_csrf. It holds a random value, expires after one day, isHttpOnlyandSameSite=Lax, and exists for a single purpose: a form submission is only accepted if the submitted form carries the same value. That is what stops a third-party page from submitting a form in your name. It is strictly necessary for the service you requested (section 25(2) no. 2 TDDDG), so there is no consent banner: there is nothing here to consent to. - A counter is incremented. For pages under
/products,/vendors,/categories,/compare,/alternatives,/integrations,/pricing,/agents,/industries,/use-cases,/finderthe site stores one row per path and calendar day with a number in it, and nothing else. No IP address, no user agent, no referrer, no timestamp per visit, no identifier that could join two visits together. Account pages, tools and search result pages are deliberately not counted, because there a number per path would be a record of one person's behaviour. - Nothing is loaded from anywhere else. There is no
analytics script, no tag manager, no advertising pixel, no embedded
video, no web font from a foreign host and no CDN. Every response
carries this policy, and your browser enforces it:
default-src 'none'; style-src 'unsafe-inline'; img-src 'self' data:; form-action 'self'; base-uri 'none'; frame-ancestors 'none'
Your IP address reaches the server, because no computer can answer without it. It is used while the request is being answered and is not written to the database. The one place it is used for longer is described under Forms below.
Search terms
When you use the search or the advisor, the words you typed are stored lowercased and shortened to 120 characters, as one row per term and calendar day with a count. That row carries no account, no session and no address, so it cannot be traced back to you. It can still contain whatever you typed, so please do not type anything into the search that you would not want stored.
Forms
These public forms exist: register, login, request, newsletter, claim, submit.
Each of them runs through a brake keyed on your IP address:
10 submissions per 10 minutes are free, each further one
waits 250 ms longer than the one before, up to
8 seconds. There is no block, no error code and no
message telling you that you were slowed down. The counter lives in the
server process only, is never written to the database, and is forgotten
when the server restarts.
If you create an account
An account stores your email address, your password as a salted scrypt hash (never the password itself), your role, an optional name, the consents you gave with the date you gave them, and the times the record was created and changed.
A login writes a session row holding the SHA-256 hash of the
session token, not the token; the cookie
tdp_sitzung holds the token, is
HttpOnly, SameSite=Lax, is sent only over
HTTPS in production, and lasts 30 days. Each login attempt
writes the email address and whether it succeeded; that is what the
deliberate delay after failed attempts is computed from. Confirmation
codes are stored as a hash and expire after 60 minutes.
Beyond the account itself, 17 tables can carry your account. This list is read from the database schema when this page is rendered, not typed here, so a new table appears in it by itself:
abonnement, alert, api_schluessel, beitrag, bestaetigungscode, einreichung, kanten_kandidat, lead, rfp_antwort, sitzung, vendor_claim, watchlist, workspace, workspace_bewertung, workspace_eintrag, workspace_ereignis, workspace_mitglied
What you put in them is what they hold: watchlists and the alerts delivered from them, workspaces with their members, entries, ratings and events, RFP answers, vendor claims and submissions, newsletter subscriptions, information requests to vendors, API keys as a hash, and editorial texts you wrote.
Every message this site sends is written to an outbox row first, holding the recipient, subject, plain text, purpose, the transport used, the time it was sent and any error. No transport is configured right now, so nothing leaves the server; the pages that would send a message say so instead of pretending. The newsletter is double opt-in: an address is only used after the confirmation link in the first message has been followed, and every message carries an unsubscribe link.
Links to vendors and affiliate links
Outbound links to vendor documentation carry
rel="nofollow noopener" and are followed only when you
click them. Where a link earns a commission, the page carrying it says
so, and only such a page says so. The redirect at /go/<id>
answers with a temporary redirect (302) and
Cache-Control: no-store, and increments one number per link
and calendar day. No address, no identifier and no timestamp per click
is recorded.
What vendors can see
A vendor who has claimed a profile sees aggregate numbers about their own products: profile views, comparison counts, the number of people watching, popular search terms. They never see who you are, because the site does not know. Aggregated buying interest per category and week is counted only for accounts that switched that consent on, only as a number, and a cell is withheld below 5 consenting accounts, because with fewer a single account could be guessed.
The error log
When a request fails, the server writes the time, the method, the requested address including its query string (up to 500 characters), the error message and the stack trace. That row can therefore contain a search term you typed, if the failure happened on a search. No IP address and no account is written with it.
How long things are kept
Straight, because a vague answer here would be worth nothing: there is no automatic deletion job yet. An expired session or an expired confirmation code stops working at once, and a used code cannot be used again, but the rows stay until the account is deleted. Deleting your account removes them, including every login attempt for your address. Counters per day, per search term and per link carry no personal data and are kept. This paragraph will change when the job exists, and not before.
Your rights
Under the GDPR you have the right of access (Article 15), to rectification (16), to erasure (17), to restriction (18), to data portability (20) and to object (21), and the right to lodge a complaint with a supervisory authority (77). Two of them are built in and need no request:
/account/exporthands you one JSON file with your account and every row in every table above that belongs to it. The tables are derived from the schema, so a table nobody remembered is still in the file. Password and token hashes are left out, because they are of no use to you and of use to a thief.- The deletion form on your account page
posts to
/account/deleteand deletes the account after you confirm with your password. What hangs below it in the database goes with it. That address takes no link, only the form: a link to it would answer with a 404, and an offered way that does not exist is worse than none.
For everything else, write to German.saas@web.de.
Where the data is, and who else touches it
The site and its database run on a server in Nuremberg, Germany, rented from Hetzner Online GmbH. As the hosting provider it is a processor within the meaning of Article 4(8) GDPR: it holds the data because the machine is theirs, and it does nothing with it on its own account. No mail provider is involved yet, because no transport is configured. There is no analytics provider, no advertising network and no third-party script, so there is nobody else in the chain. Nothing is transferred to a country outside the European Union.