What AdHole does with your data

This is a translation. The French version is the reference; in case of discrepancy, the French
version prevails. French version: CONFIDENTIALITE.txt, shipped with the program.

Version 2.8 — 17 September 2026

Short answer: nothing about your browsing leaves your computer, or your phone, for the
publisher. Only an anonymous statistic reaches the publisher — to count installations, and to
show on the website the total number of requests blocked —, and it can be turned off in the
settings.

This document describes the computer program first. The "On Android" section says what changes, and
what does not, in the app for Android phones and boxes.

What is processed, and where

AdHole necessarily sees a lot: that is the price of filtering that works. It sees the domain names
your machine requests, and the content of the web pages your browser loads, except for the sites
deliberately left undecrypted. All this processing takes place on your machine, in the
program's memory, for the duration of the request.

It also sees the domain names requested by the other devices you point at this PC: television,
console, phones. Their local IP address appears in the dashboard.

What is kept

Everything written to disk is written in AdHole's data folder:
C:\ProgramData\adhole on Windows, /var/lib/adhole on Linux.

- The last 1,000 requests shown in the dashboard, with the IP address of the device that sent them
    Where, in the data folder — nowhere: RAM only
    How long — until the service stops

- The dashboard's detailed counters: cache, latency, rankings of domains and devices
    Where, in the data folder — nowhere: RAM only
    How long — until the service stops

- Technical log
    Where, in the data folder — logs
    How long — rotated beyond 10 MB; the previous version is kept alongside

- Downloaded filter lists
    Where, in the data folder — lists
    How long — replaced at each refresh

- Root certificate and its private key
    Where, in the data folder — ca
    How long — until uninstallation, and beyond if you do not delete the data folder

- The network's address assignments, with the hardware address and the name of each device — only if
  you have enabled address distribution
    Where, in the data folder — baux-dhcp.json
    How long — until the file is deleted

- Your custom rules and settings
    Where, in the data folder — at the root of the folder
    How long — until deleted

- Request totals — seen, blocked, the network filter's share, the proxy's share — and the date the
  count started: numbers only, no domain name, no address, no request time
    Where, in the data folder — compteurs.json
    How long — until the file or the data folder is deleted

- The anonymous statistic's number and the mark of its last send — only if the anonymous statistic
  is on
    Where, in the data folder — mesure.json
    How long — until the statistic is turned off, which deletes the file

No browsing history is written to disk. Restarting the service erases the latest requests, the
rankings, the cache and the latency. Only the totals survive, in compteurs.json: numbers, with
nothing of what was asked for. The technical log does not contain the pages visited; it may contain
domain names in the event of an error, and more if you run the program with the -debug option.

What is not done

- No data about your browsing is sent to the publisher. Only the DNS resolvers see the names of
  the sites requested — and your router, in plain text, when no encrypted resolver answers any
  more (see "The program's only outgoing connections").
- No account, no persistent identifier, no tracker: the only measurement is the anonymous
  statistic described below.
- No resale, no sharing: there is nothing to sell, and nothing about your browsing reaches the
  publisher.
- The dashboard loads no remote resource: everything is served from your machine.

The anonymous statistic

What is sent. Shortly after each start of the service, then once a day, with the version check
(point 4 below): a number drawn at random on
your computer and renewed every month (file mesure.json in the data folder), AdHole's version
number, the system with its processor type (for example windows-amd64), and the number of requests
blocked since the previous check. Nothing else: no name,
no hardware address, no site visited.

That number of blocked requests, precisely. It is a plain number — 4128, say — and it goes out
only together with the identifier: no domain name, no address, no browsing date goes with it, and it
says nothing about what was blocked. It is a difference since the last accepted send, never a
running total: the mark of that send is kept in the same mesure.json file, so the monthly change
of identifier does not make the same installation be counted again. The dashboard totals, for their
part, survive a restart of the service: they are kept on your disk, in compteurs.json, and
contain nothing but numbers. What goes out is still the difference since the last accepted send,
never that total.

Why. To know how many installations are active each day, each week and each month, on which
systems and in which versions. The number of blocked requests serves one purpose only: to show on
the AdHole website the total number of advertising and tracking requests blocked across all
installations. The server also counts the downloads of each published file, without
keeping anything about the person downloading.

What the server keeps. Totals, per day and per month, and a single grand total for blocked
requests, added up with no link to the installation that sent it and without keeping the send
itself; a send announcing more than ten million requests is discarded. So as not to count the same installation
twice, it keeps a fingerprint of the number, computed with a secret key that never leaves the
server and does not allow the number to be recovered: seven days for the weekly count, until the
end of the month for the monthly count, after which it is erased. No IP address is recorded:
the server keeps no log of these connections and writes no address to its disk. To reject numbers
invented in bursts, it only keeps in memory a fingerprint of the address, computed with the same
secret key, and the number of new numbers it has presented during the day (50 at most). This
fingerprint is forgotten at the first contact of the following day (UTC), or when the server
restarts.

Who is responsible. The publisher is the controller of this processing, which is based on his
legitimate interest in knowing how his software is used (Article 6(1)(f) of Regulation (EU)
2016/679). He limits it to the conditions that the CNIL (the French data protection authority)
accepts for audience measurement exempt from consent: purpose limited to counting, aggregated
results, number renewed every month, no transmission to a third party, and the possibility to
object at any time. The server is hosted by the provider indicated in MENTIONS-LEGALES.txt
(English: MENTIONS-LEGALES.en.txt).

How to turn it off. The "Anonymous statistics" switch in the dashboard settings ("Statistiques
anonymes" in the French interface), or mesure_audience: false in config.yaml: the identifier is
immediately erased from your disk — along with the mark of the last send, which is in the same
file —, the number of blocked requests stops being sent, and the version check goes out on its own.
The compteurs.json file is not deleted: the dashboard totals keep being counted and kept on your
disk, only nothing from them goes to the publisher any more. Emptying the update address
additionally cuts any connection to the publisher's server.

The program's only outgoing connections

1. The DNS resolvers, encrypted by default: DNS-over-HTTPS with Cloudflare, then DNS-over-TLS
   with Quad9 if Cloudflare has not answered within a second; the first answer received is used.
   As long as they answer, your internet service provider does not see the names you look up; the
   resolver that answers does. When none of them answers any more, your router takes over and your
   provider sees them again: that is the next point. The default list ends with an unencrypted
   last-resort resolver, 1.1.1.1 (Cloudflare), queried only when the encrypted resolvers still have
   not answered, three seconds after the first request: those queries travel in plain text. You can
   change resolver, or remove that one, in the settings.
2. Your network's router, only when all the resolvers above have failed three times in a row.
   AdHole then puts your questions to it, in plain text: your internet service provider sees
   them again, as it did before the installation. This is a stopgap, and we say so — it goes around
   the encryption you chose, because a name resolved in plain text is better than a computer with
   no internet. It lasts no longer than the outage: every ten seconds, AdHole tries the encrypted
   resolvers again and goes back to them as soon as one answers. Filtering does not change in the
   meantime — an advertising domain is blocked before the question goes out, so it stays blocked.
   The router is detected automatically; failing that, the resolver you set for local names is used.
   AdHole never falls back on itself, nor on a resolver already in your list. The service log records the start and the end of each fallback, with its
   duration.
3. The filter lists, downloaded once a day from their authors (AdGuard, hagezi) or from GitHub,
   which hosts some of them. These servers see your IP address, as with any download. Each list
   can be disabled.
4. The version check, shortly after each start of the service then once a day: a small file
   indicating the latest published version, on the publisher's server (adhole.io), accompanied by
   the anonymous statistic if it is on. This server sees your IP address and does not record it
   (see "The anonymous statistic").
5. The download of the installer, when an update exists and automatic installation is on, from
   the address that this file indicates.

Points 4 and 5 are disabled by emptying the update address in the config.yaml file in the data
folder.

On Windows, when AdHole does not answer in time, the computer directly queries the fallback resolver
set at installation — your router, or 1.1.1.1 if it could not be found —, in plain text and without
filtering.

The resolvers, the list authors and GitHub are third parties: each is responsible, on its side, for what it
does with the IP addresses it sees, and AdHole's publisher has no access to them.

On Android

The Android app filters on the device. It declares itself to Android as a local virtual private
network — a local VPN — and, since version 1.5.0, all of the phone's traffic goes through it, on
the phone. That tunnel leads nowhere outside the device: what enters it is handled on the spot,
then leaves the phone for its real destination. AdHole routes your traffic through no server, does
not hide your IP address, and routes none of your data through the publisher.

What it sees. Two things, and not one more:

- the domain names the device asks for, for every app;
- the content of the pages you open in your browsers, if you have installed its root certificate
  (terms of use, art. 5.6). It opens them to hide ad slots, refuse cookie banners and take the ads
  off YouTube videos. This applies only to the browsers you leave ticked in the settings, and never
  to the sites left encrypted.

What it does not see. The content of the traffic of apps other than browsers: Android does not
let one app read another's encrypted traffic, and AdHole does not try — those connections are
relayed as they are, byte for byte. Nor the content of the sites left encrypted, in a browser as
anywhere else. And as long as the certificate is not installed, or if you turn off the "Remove ads
and cookie banners in browsers" setting, no page is opened: the app then sees domain names only.

All of that processing happens on the device, in memory, for the time of the request or the
page.

What is written on the device. In the app's private data folder, which Android keeps apart from
other apps, and nowhere else:

- The latest requests shown in the app, and the counters of the current session: ranking of blocked
  domains, cache, latency
    Where — nowhere: RAM only
    For how long — until filtering stops

- Your custom rules and your settings (chosen resolvers, filtered browsers, sites left encrypted,
  anonymous statistic)
    Where — at the root of the folder
    For how long — until deleted

- The list of your filter lists, and the downloaded lists
    Where — in the folder
    For how long — replaced at each refresh

- The root certificate and its private key — created the first time you tap "Install the
  certificate"
    Where — ca
    For how long — until the app is uninstalled

- Request totals — seen and blocked — and the date the count started: numbers only, no domain name,
  no address, no request time
    Where — compteurs.json
    For how long — until the file or the data folder is deleted, or the counters are reset

- The number used by the anonymous statistic and the mark of its last send — only if the anonymous
  statistic is on
    Where — mesure.json
    For how long — until you turn the statistic off, which deletes the file

No browsing history is written on the device, and the content of the pages that are opened is
never kept: it is handled in memory, for the time of the page. The latest requests shown in the
app, the ranking of blocked domains, the cache and the latency live in memory and disappear when
filtering stops. Only the totals survive, in compteurs.json: numbers, with nothing of what was
asked for. That running total is what the home screen shows, because on a phone filtering stops
several times a day and the counters used to start again from zero each time. The button that
resets the counters deletes that file too.

The certificate's private key never leaves the device. It is created on the phone; the publisher
has no copy of it and cannot obtain one. Do not copy the app's data folder anywhere: anyone who got
hold of that key could pass themselves off as any site, for this phone.

The outgoing connections are the same as on a computer (see the previous section): the encrypted
DNS resolvers, the fallback in plain text when they have all gone down, the download of the filter
lists, and the version check together with the anonymous statistic. The fifth one is the exception:
the app never downloads an update by itself — you start it, and Android installs it.

The fallback does exist on Android, and on a phone it is not always "the router". When all your
encrypted resolvers have failed three times in a row, the app puts your questions to the resolver of
the network the phone is attached to, in plain text, for as long as the outage lasts: your
router over Wi-Fi, your mobile operator's relay on mobile data, the operator's own on a public
Wi-Fi. So that is who sees those names — on a mobile network, your operator; on a public Wi-Fi,
whoever runs it. This fallback goes around the encryption you chose: it is a stopgap, so as not to
leave you with no name resolution at all. The app goes back to encrypted the moment a resolver
answers, and filtering does not stop in the meantime. It follows the network: when the phone moves
from Wi-Fi to mobile data, the new network's resolver takes over.

The anonymous statistic is identical — a number drawn at random and renewed every month, the
version, the system, here android (or android-tv on a box), and the number of requests blocked
since the previous check, which feeds the total shown on the website. It is on by default and can be
turned off in the app's settings: the identifier is then erased from the device, and that number
stops being sent.

You can turn filtering off at any time, from the app's home screen or by withdrawing its
permission in Android's settings. The device's traffic goes back to normal at once. You can also
turn off page cleaning alone, with its switch in the settings: domain-name filtering carries on, and
no page is opened any more.

Uninstalling the app takes its data folder with it, and so the private key. The root certificate
you installed stays in Android's store: Android does not let an app remove it. Take it out under
Settings → Security → User credentials, then adhole Root CA.

Who is responsible for what

The publisher is not the controller of any processing relating to your browsing, within the
meaning of Regulation (EU) 2016/679: no browsing data reaches the publisher, and he has no technical
means of obtaining any. He is the controller of a single processing operation: the anonymous
statistic described above.

You remain in control of the data that passes through your machine. As long as the use remains
strictly personal or household, it falls outside the European regulation under its Article
2(2)(c). As soon as the filter is used elsewhere — a shop, an association, a work computer, a
third party's network —, it is you who become the controller of the processing of the requests from
the devices concerned, and it is up to you to inform the people who use them.

The sites left encrypted

Some sites are never decrypted: AdHole opens a plain tunnel and sees nothing of their content. A
default list is shipped with the program; it covers in particular system updates, game stores,
storage services, encrypted messaging services, payment services and video streams.

This list cannot be exhaustive, and the publisher does not claim that it is: no publisher can
list every bank, mutual health insurer or government body in the world. The list actually applied
on your machine can be viewed and edited in the dashboard settings, in the section on sites left
encrypted (no_decrypt in the configuration file); on Android, in the app's settings, under "Sites
left encrypted". The starting list there is the same as on a computer, and it works the same way:
those sites are never opened, not even in a browser.

It is up to you to add the sites you do not want to see decrypted — bank, health, taxes,
employer. Take that minute before your next sensitive login.

Erasing everything

On a computer, uninstalling removes the service, the certificate and the proxy. On Windows, the
installer then offers to delete the data folder; if you decline, the certificate's private key
stays there. On Linux, there is no installer: the restoration is done by hand, and the data folder
remains until you delete it.

On Android, uninstalling the app takes its data folder with it, private key included. One gesture
is left to make: take the root certificate out of Android's store, under Settings → Security →
User credentials.

    adhole teardown          (Windows, administrator command prompt)
    sudo adhole teardown     (Linux)

then delete the data folder.

Contact

For any question about personal data: contact@antoinemoury.fr.
Full identity of the publisher: MENTIONS-LEGALES.txt (English: MENTIONS-LEGALES.en.txt).
