Client Specifications¶
Foreword¶
For years, the sole and unique client was Gecko (the platform behind Firefox, Thunderbird..). In order to reach out new platforms and products, a fully-featured Rust client was built, using the application-services components (Viaduct, NSS, …). Despite our efforts to provide this fully featured, cross-platform client, new clients still emerged that obliged us to admit that our idea of having a single client of reference is dead. Instead, we are going to provide specifications for Remote Settings clients, to at least mitigate the consequences of clients fragmentation.
That being said, we still strongly discourage the implementation of new ad-hoc clients.
We distinguish two major use-cases:
authenticated write operations, ie. publish data;
anonymous read operations, ie. fetch data from within our products.
Since the former does not take place on clients, it matters less than the latter, which has a major impact on traffic and our servers load.
Before launching your own implementation, please keep in consideration that:
client fragmentation hinders our cohesive view of the service (from server to clients)
heterogenous implementations slow down the roll out of API changes
having multiple code bases for one service raises the cost of code review, maintenance, support, feature parity, security assurance
the Remote Settings team has to be consulted to validate the implementation
Existing Clients¶
As of January 2025:
Gecko |
application-services/remote-settings |
kinto-http.py |
kinto.js |
|
---|---|---|---|---|
Write Operations |
❌ |
❌ |
✅ |
✅ |
Add/Remove Attachments |
❌ |
❌ |
✅ |
✅ |
Approve/Reject reviews |
❌ |
❌ |
✅ |
❌ |
Changesets Endpoints |
✅ |
✅ |
✅ |
❌ |
Cache Busting |
✅ |
❌ |
✅ |
❌ |
Env Switching |
✅ |
✅ |
❌ |
❌ |
Signature Verification |
✅ |
✅ Optional |
❌ |
❌ |
Local cache |
✅ |
✅ |
❌ |
✅ |
Push notifications |
✅ |
❌ |
N/A |
N/A |
Fetch Attachments |
✅ |
✅ Without integrity check |
✅ |
✅ |
Attachments bundles |
✅ |
❌ |
❌ |
❌ |
JEXL support |
✅ |
✅ Optional |
N/A |
N/A |
Packaged binary dumps |
✅ |
✅ |
N/A |
N/A |
Uptake telemetry |
✅ |
❌ |
N/A |
N/A |
Backoff |
✅ |
✅ |
✅ |
✅ |
Deprecation |
❌ |
❌ |
✅ Minimal |
✅ |
Pagination |
❌ |
❌ |
✅ |
✅ |
Specifications¶
Remote Settings is a layer on top of the Kinto API. Although every read-only operation offered by the Kinto API is available on our Remote Settings server, clients must restrict the amount of distinct interactions. Millions of devices sending arbitrary requests could have a significant impact on infrastructure.
That’s why clients developers MUST keep their implementation as close as possible to the existing ones, or at least get in touch with us if there is a solid reason to derive from it.
Endpoints¶
Clients MUST set their User-Agent
request header, mentioning application name and version.
Clients SHOULD leverage Gzip transport using the Accept-Encoding: gzip
request header.
The following two endpoints MUST be used to retrieve data. Clients MUST NOT use other endpoints.
Fetch collection:
GET /v1/buckets/{bid}/collections/{cid}/changeset?_expected={timestamp}
.
Returns the following response for the collection {cid}
in the bucket {bid}
(likely main
):
changes
: list of records, optionally filtered with?_since="{timestamp}"
metadata
: collection attributestimestamp
: records timestamp
Note
The _expected={}
querystring parameter is mandatory. Either you pass the current collection timestamp value obtained when polling for changes in order to bust the CDN cache, or you use a hard-coded value (eg. 0
) and rely on the cache TTL. See section below about cache busting.
Examples:
Clients SHOULD NOT rely on arbitrary server side filtering. In Remote Settings, collections are quite small anyway, and can usually be fetched entirely to be filtered on the client side. This helps us reduce our CDN cache cardinality.
Client MAY filter the list of changes to only obtain the changes since the last polling, using the ?_since=
querystring parameter. The value is a timestamp obtained from a previous changeset response.
For each collection, the amount of possible values for the timestamps is finite. Indeed, each timestamp value corresponds to the date and time of the data publication (reviewer approving changes on the server). Some collections change several times a day, but that still allows a lot of caching. The push notifications are debounced too, in case several users approve changes in a short amount of time.
Poll for changes:
GET /v1/buckets/monitor/collections/changes/changeset?_expected={timestamp}
.
Returns the list of collections and their current timestamp.
changes
: list of collections and their timestamp, optionally filtered with?_since="{timestamp}"
timestamp
: highest collections timestamp
Note
The _expected={}
querystring parameter is mandatory. Either you receive a Push notification from the server, and pass the timestamp value in order to bust the CDN cache, or you use a hard-coded value (eg. 0
) and rely on the cache TTL. See section below about cache busting.
{
"metadata": {},
"timestamp": 1713532462683,
"changes": [
{
"id": "19e79f22-62cf-92e1-c12c-a3b4b9cf51be",
"last_modified": 1603126502200,
"bucket": "blocklists",
"collection": "plugins",
"host": "firefox.settings.services.mozilla.com"
},
{
"id": "b7f595f9-5fc5-d863-b5dd-e5425dcf427a",
"last_modified": 1604940558744,
"bucket": "blocklists",
"collection": "addons",
"host": "firefox.settings.services.mozilla.com"
}
]
}
Examples:
Server Error Responses¶
Every response is JSON.
If the HTTP status is not OK (>=400), the response contains a JSON mapping, with the following attributes:
code
: matches the HTTP status code (e.g400
)errno
: stable application-level error number (e.g.109
)error
: string description of error type (e.g."Bad request"
)message
: context information (e.g."Invalid request parameters"
)info
: online resource (e.g. URL to error details)details
: additional details (e.g. list of validation errors)
Example response
{
"code": 400,
"errno": 107,
"error": "Invalid parameters",
"message": "_since in querystring: The value should be integer between double quotes.",
"details": [
{
"location": "querystring",
"name": "_since",
"description": "The value should be integer between double quotes."
}
]
}
Cache Busting¶
Using push notifications
With push notification, we want the first requests to bust the CDN cache of the polling endpoint with the received value.
The push notification payload contains the highest of all collections
This timestamp is passed to the
?_expected={}
querystring param when polling for changesThe polling endpoint will return the list of collections with their respective timestamps (last_modified field):
Each collection can now be fetched using the timestamp obtained from the polling endpoint (eg. using the above example:
/buckets/blocklists/plugins/changeset?_expected=1603126502200
)

Without push notifications (cached polling)
Without push notification, we use hard-coded value (?_expected=0
) and rely on the cache TTL of the polling endpoint.
And use the timestamps obtained in the polling endpoint response as described above with push notifications.

Without push notifications nor polling for changes (cached fetching)
With this approach, we skip the step that poll for changes, and rely on the cache TTL for the collection data.

Note
As the service owners, we don’t guarantee that we will keep the collection TTL under X hours.
Environment Switching¶
Clients MAY offer a convenient way to switch between DEV, STAGE, or PROD environments, in order to facilitate the work of QA teams.
Clients SHOULD use PROD by default. And for security reasons, there must be some protection in place to prevent users to switch environments.
Signature Verification¶
Clients SHOULD verify the integrity of the downloaded data.
Signature verification allows to guarantee:
authenticity (+integrity) of data obtained from the server;
that client local data was not tempered between two syncs.
Note
Although Gecko on desktop is not exposed to the same risks as on mobile where applications and data are jailed, verifying signatures is a keystone in the chain of trust for data that we pull from remote servers.

Signature validation steps are:
Download the certificates chain provided from the
x5u
URL in metadata, and parse the PEM bytes as DER-encoded X.509 CertificateVerify the certificates chain:
each certificate must be valid at the current date
each child signature must match its parent’s public key for each pair in the chain
root certificate must match hard-coded value
Verify that the subject alternate name of the chain’s end-entity (leaf) certificate matches the
signer_id
provided in metadataUse the chain’s end-entity (leaf) certificate to verify that the “signature” value provided in metadata matches the contents of the local data:
Serialize the local data
{"data": records_sorted_by_id, "last_modified": timestamp}
using Canonical JSONThe message to verify is the concatenation of
Content-Signature:\x00 + serialized_data
Decode the base64
signature
string provided in metadata (using URL safe)Verify using the leaf certificate public key that the message matches the decoded signature using the ECDSA_P384_SHA384_FIXED algorithm
Examples with 3rd party crypto library:
Clients embedded in products SHOULD use NSS (true in ~2023), and its high level API for signature verification.
Examples with Mozilla NSS:
Local State¶
Clients MAY have a local state and copy of the data, in order to limit the amount of data to fetch from the server.
The local state SHOULD contain the timestamp of the last successful fetch, to be provided in the ?_since=
filter on the next call. The deleted records are then returned in the form of tombstones ({"id": "xyz", "deleted": true}
), which MUST be removed from local copy. Created and updated records are returned in the same form and MUST be upserted in local copy.
Examples:
Attachments¶
The attachments base URL is obtained on the root URL of the server:
GET /v1/
Returns the metadata of the server.
capabilities.attachments.base_url
: the base URL for attachments with a trailing/
Records with an attachment have the necessary metadata to download and verify it.
attachment.location
: path to the attachment, to be concatenated with thebase_url
attachment.hash
: SHA-256 of the fileattachment.size
: size of the file in bytes
Clients SHOULD verify the size and hash of their downloaded copy in order to implement our security model and guarantee integrity and authenticity of CDN content.
Examples:
Attachments bundles¶
For collections where attachments bundling is enabled, the clients can download a Zip bundle:
GET {{ attachments.base_url }}/bundles/{{ bucket }}--{{ collection }}.zip
It returns a Zip with the attachment files and their metadata, and can be used to fill the local attachment cache using a single network request.
Filenames are:
{record[id]}
for the attachment binary data{record[id]}.meta.json
for the metadata
Note
In order to avoid facing a 404 when pulling the bundle, and know in advance whether a collection has a bundle available,
check the attachment.bundle
field in the collection metadata
(eg. from the changeset endpoint).
$ curl -s "$SERVER/buckets/security-state/collections/intermediates/changeset?_expected=0" | jq .metadata.attachment.bundle
true
Examples:
Push Notifications¶
Clients MAY listen to push notifications from and initiate synchronizations when a payload is received.
The broadcast ID is "remote-settings/monitor_changes"
and the PROD server wss://push.services.mozilla.com
.
The payload contains the highest timestamp of all collections as quoted string (ie. ETag). See the Cache busting section on how to use the received timestamp.
Examples:
Uptake Telemetry¶
Clients MAY report the status of the synchronization:
up-to-date
success
error
See additional statuses in Desktop clients.
Clients MAY report synchronization status for the following sources:
"settings-sync"
: as a global synchronization status"settings-changes-monitoring"
: for polling frommonitor/changes
{bucket}/{id}
: for the synchronization of a single collection
Clients MAY attach additional information like:
duration
: duration of synchronization in millisecondstimestamp
: current timestamp valuetrigger
: what triggered the synchronization (startup
,timer
,broadcast
,manual
)errorName
: an error identifier, such as the exception class name
Backoff Headers¶
As owners of the backend, we want to be able to tell clients to gently delay their hits on the server.
Client MUST honour the wait interval in seconds set in the Backoff
response headers.
Examples:
Deprecation Headers¶
Client SHOULD react on deprecation headers. Ideally make it visible to the final users that the version of their product is relying on a service that is going away.
When enabled, the server sends a Alert
header with a JSON serialized value, that contains extra-information (eg. message
, url
).
Examples:
Documentation: