diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..428b0c8
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,6 @@
+repos:
+-   repo: https://github.com/Lucas-C/pre-commit-hooks-nodejs
+    rev: v1.1.2
+    hooks:
+    -   id: markdown-toc
+
diff --git a/README.md b/README.md
index 1d3a37b..f6c03a6 100644
--- a/README.md
+++ b/README.md
@@ -7,11 +7,15 @@
 GPSTracker is a simple Webapp that consists of:
 
 - A backend that:
-  - Can read GPS data from any compatible data source (supported: `postgres`, `mysql`, `mariadb`, `mongodb`, `sqlite`,
-    `snowflake`), with arbitrary complex filtering, and expose them over a simple Web API.
-  - [[*TODO*]] Can ingest GPS data points from HTTP, MQTT, Websocket or Kafka.
+  - Can manage GPS data stored on a local db or on any compatible data source
+    (supported: `postgres`, `mysql`, `mariadb`, `mongodb`, `sqlite`,
+    `snowflake`), with arbitrary complex filtering, and expose them over a
+    simple Web API.
+  - Can ingest GPS location updates from HTTP.
 - A frontend to display GPS data points and provides advanced filtering.
 
+It is meant as a self-hosted and privacy-aware alternative to services like Google Maps Timeline.
+
 ![Screenshot of GPSTracker](https://static.platypush.tech/screenshots/gpstracker_screenshot.jpg)
 
 ## Configuration
@@ -59,6 +63,81 @@ make frontend
 npm run start
 ```
 
+## Usage
+
+### Initial setup
+
+Once the application is running, you can access the frontend at
+`http://localhost:3000` - or on whatever port you configured in the `.env`
+file.
+
+Use the `ADMIN_EMAIL` and `ADMIN_PASSWORD` values from the `.env` file to log
+in.
+
+You can then create a new device for your GPS data under the `Devices` menu, or
+at `http://localhost:3000/devices`. Take note of the `deviceId`, you will need
+it to ingest data.
+
+Then create a new API token from the `API` menu, or at
+`http://localhost:3000/api`.
+
+### Ingestion
+
+The application exposes a POST endpoint at `/gpsdata` that accepts a JSON
+payload containing the GPS data to ingest. Example:
+
+```bash
+curl -XPOST \
+  -H "Authorization: Bearer your-api-token" \
+  -H "Content-Type: application/json"
+  -d '[{
+      "deviceId": "your-device-id",
+      "latitude": 40.7128,
+      "longitude": -74.0060,
+      "address": "260 Broadway",
+      "locality": "New York, NY",
+      "country": "us",
+      "postalCode": "10007",
+      "description": "New York City Hall",
+      "timestamp": "2021-01-01T00:00:00Z"
+    }]' http://localhost:3000/api/v1/gpsdata
+```
+
+You can wrap this in a script to ingest data from a file, or from a GPS tracker.
+
+You can also configure a mobile app like [GPSLogger](https://gpslogger.app/) to
+periodically send data to the endpoint - select _Custom URL_ and use the
+`/gpsdata` endpoint with the API token as the `Authorization` header under the
+_HTTP Headers_ section.
+
+Or, for more advanced use cases, you can use a general-purpose application like
+[Tasker](https://tasker.joaoapps.com/) in combination with
+[AutoLocation](https://play.google.com/store/apps/details?id=com.joaomgcd.autolocation)
+to send data to the endpoint, or decouple the ingestion from the frontend by
+using an intermediate MQTT or Kafka broker.
+
+### External data sources
+
+By default, the application will store the GPS data under the configured
+`DB_URL` database.
+
+If you have an existing database with GPS data, you can configure it in the
+`.env` file through the `DB_LOCATION_URL` variable. The application will then
+read the data from the external source and expose it through the API.
+
+Consult the `.env.example` file if the column names in your database differ from
+the default ones.
+
+Note however that:
+
+- The external data source must have a `deviceId` column (or whatever column
+  name you configured in the `.env` file) that uniquely identifies the device
+  that generated the data, and it must point to a valid device in the
+  application database.
+
+- Changes to the ownership of the devices or deletion of devices in the
+  application database will not be reflected in the external data source.
+
 ## Development
 
 ### Compile and Hot-Reload for Development