Envelopes
This document defines the Envelope and Item formats used by Sentry for data ingestion, forwarding, and offline storage. The target audience of this document is Sentry SDK developers and maintainers of the ingestion pipeline.
Backward Compatibility
Envelopes require Relay, which has been introduced in Sentry v20.6.0. Earlier versions of Sentry do not support Envelopes and respond with HTTP error 404 Not Found to envelope uploads. Likewise, Relay requires support for Envelopes on the upstream and cannot be used with older versions of Sentry.
Envelopes are a data format similar to HTTP form data, comprising common Headers and a set of Items with their own headers and payloads. Envelopes are optimized for fast parsing and human readability. They support a combination of multiple Items in a single payload, such as:
- Submit events with large binary attachments.
- Enable communication between hops, for instance, between different SDKs (Native and Mobile, ReactNative and Android) and between Relays.
- Allow batching of certain Items into a single submission.
- Offline storage for deferred sending after connection issues.
Sentry specifies a dedicated endpoint at for ingesting Envelopes:
POST /api/<project_id>/envelope/
Terminology
- required: The implementation may emit an error if this field is missing.
- recommended: This field should be emitted when writing, but can be missing during a read.
- optional: Can be omitted freely during writing and can be missing during a read.
Serialization Format
This section defines the Envelope data format and serialization. For details on data integrity and a list of valid Item types refer to the next section Data Model.
Prerequisites
These definitions apply to all parts of the Envelope data format:
- Newlines are defined as UNIX newlines, represented by
\n
and ASCII code 10. If newlines are preceded with\r
, this character is considered part of the previous line or payload and may emit an error. - UUIDs are declared as either 32 character hexadecimal strings without dashes
(
"12c2d058d58442709aa2eca08bf20986"
), or 36 character strings with dashes ("12c2d058-d584-4270-9aa2-eca08bf20986"
). It is recommended to omit dashes and use UUID v4 in all cases. - Envelopes do not offer a mechanism for compression. However, an entire Envelope may be compressed or decompressed in an implementation defined way by any component handling Envelopes. For example, Ingestion allows compression via content encoding.
Headers
Envelopes contain Headers in several places. Headers are JSON-encoded objects (key-value mappings) that follow these rules:
- Always encoded in UTF-8
- Must be valid JSON
- Must be declared in a single line; no newlines
- Always followed by a newline (
\n
) or the end of the file - Must not be padded by leading or trailing whitespace
- Should be serialized in their most compact form without additional white space. Whitespace within the JSON headers is permitted, though discouraged.
- Unknown attributes are allowed and should be retained by all implementations; however, attributes not covered in this spec must not be actively emitted by any implementation.
- All known headers and their data types can be validated by an implementation; if validation fails, the Envelope may be rejected as malformed.
- Empty headers
{}
are technically valid
Header-only Example:
{"event_id":"12c2d058d58442709aa2eca08bf20986"}
Envelopes
The full grammar for an Envelope is:
Envelope = Headers { "\n" Item } [ "\n" ] ;
Item = Headers "\n" Payload ;
Payload = { * } ;
- Headers are a single line containing a JSON object, as defined in the Headers section. Attributes defined in the Envelope header scope the contents of the Envelope and can be thought of as applying to all Items.
- Based on the contents of the Envelope, certain header attributes may be required. See Data Model for a specification of required attributes.
- Items comprise their own headers and a payload. There can be an arbitrary number of Items in an Envelope separated by a newline. An implementation should consume Items until the file ends.
- Envelopes should be terminated with a trailing newline. This newline is optional. After the final newline, no whitespace is allowed.
- Envelopes may be empty, terminating immediately after the headers.
- The end of file (EOF) does not implicitly terminate an Envelope if more data is expected, such as a Payload.
Envelope Headers
Envelopes can have a number of headers which are valid in all situations:
dsn
- String, recommended. An envelope can be self authenticated. This means that the envelope has all the information necessary to be sent to sentry. In this case the full DSN must be stored in this key.
sdk
- Object, recommended. This can carry the same payload as the
sdk
interface in the event payload but can be carried for all events. This means that SDK information can be carried for minidumps, session data and other submissions.
sent_at
- String, recommended. The timestamp when the event was sent from the SDK as string in RFC 3339 format. Used for clock drift correction of the event timestamp. The time zone must be UTC.
Implementation Guidance for the sent_at Header
It is recommend to always send the sent_at
envelope header. Do not try to determine
whether it should be sent or not, as that determination can be made on the receiving side.
The timestamp should be generated as close as possible to the transmision of the event, so that the delay between sending the envelope and receiving it on the server-side is minimized. This is usually accomplished in serialization of the envelope header.
However, care must be taken that the header is only applied once. If more than one sent_at
header is written, Sentry will reject the entire envelope. For example, SDKs that implement
caching features should avoid writing the sent_at
header when caching to disk.
Only write it when actually sending the event to Sentry.
The timestamp can be generated by any of the following (for example):
- JavaScript
new Date().toISOString()
- Python
datetime.now(timezone.utc).isoformat()
Don't usedatetime.utcnow()
, as it will omit the time zone.
- .NET
DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)
orDateTimeOffset.UtcNow.ToString("o", CultureInfo.InvariantCulture)
- Java
Instant.now().toString()
Also note that the sent_at
header replaces the sentry_timestamp
key previously set in authorization headers,
which has now been fully deprecated. You should only send sent_at
, and not sentry_timestamp
.
Items
Items supply the data of an Envelope. Without Items, an Envelope is considered empty and can safely be discarded.
There are two generic headers for every Item:
type
- String, required. Specifies the type of this Item and its contents. Based on the Item type, more headers may be required. See Data Model for a list of all Item types.
length
- int, recommended. The length of the payload in bytes. If no
length
is specified, the payload implicitly goes to the next newline. For payloads containing newline characters, thelength
must be specified.
On omitting `length`
If the Envelope contains a large number of very small Items, omitting the length can be beneficial for compression. This is the case for sessions.
The implementor should assess this on a per-case basis and explicitly argue about the decision.
Notes for implementors:
- Envelope header is required, but it can be empty.
- Implementations must gracefully skip and retain Items of unknown type, along with their payload.
- Unknown attributes must be forwarded to the upstream.
- Length-prefixed payloads must terminate with
\n
or EOF. The newline is not considered part of the payload. Any other character, including whitespace, means the Envelope is malformed. - If
length
cannot be consumed, that is, the Envelope is EOF before the number of bytes has been consumed, then the Envelope is malformed. - If an Item with implicit length is terminated by
\r\n
, then\r
is considered an arbitrary character not part of the newline, and thus part of the payload.
Full Examples
These examples contain full Envelope payloads. Newlines are explicitly marked
with \n
, unprintable characters are escaped with \x<><>
. all other
characters are literal.
Envelope with 2 Items:
Note that the attachment contains a Windows newline at the end of its
payload which is included in length
:
{"event_id":"9ec79c33ec9942ab8353589fcb2e04dc","dsn":"https://e12d836b15bb49d7bbf99e64295d995b:@sentry.io/42"}\n
{"type":"attachment","length":10,"content_type":"text/plain","filename":"hello.txt"}\n
\xef\xbb\xbfHello\r\n\n
{"type":"event","length":41,"content_type":"application/json","filename":"application.log"}\n
{"message":"hello world","level":"error"}\n
Envelope with 2 Items, last newline omitted:
Note that the attachment contains a Windows newline at the end of its
payload which is included in length
:
{"event_id":"9ec79c33ec9942ab8353589fcb2e04dc","dsn":"https://e12d836b15bb49d7bbf99e64295d995b:@sentry.io/42"}\n
{"type":"attachment","length":10,"content_type":"text/plain","filename":"hello.txt"}\n
\xef\xbb\xbfHello\r\n\n
{"type":"event","length":41,"content_type":"application/json","filename":"application.log"}\n
{"message":"hello world","level":"error"}
Envelope with 2 empty attachments:
{"event_id":"9ec79c33ec9942ab8353589fcb2e04dc"}\n
{"type":"attachment","length":0}\n
\n
{"type":"attachment","length":0}\n
\n
Envelope with 2 empty attachments, last newline omitted:
{"event_id":"9ec79c33ec9942ab8353589fcb2e04dc"}\n
{"type":"attachment","length":0}\n
\n
{"type":"attachment","length":0}\n
Item with implicit length, terminated by newline:
{"event_id":"9ec79c33ec9942ab8353589fcb2e04dc"}\n
{"type":"attachment"}\n
helloworld\n
Item with implicit length, last newline omitted, terminated by EOF:
{"event_id":"9ec79c33ec9942ab8353589fcb2e04dc"}\n
{"type":"attachment"}\n
helloworld
Envelope without headers, implicit length, last newline omitted, terminated by EOF:
{}\n
{"type":"session"}\n
{"started": "2020-02-07T14:16:00Z","attrs":{"release":"sentry-test@1.0.0"}}
Data Model
Each Envelope consists of headers and a potentially empty list of Items, each with their own headers. Which Headers are required depends on the Items in an Envelope. This section describes all Item types and their respective required headers. It is worth noting that the list of Item types doesn't match the data categories used for rate limiting and client reports.
The type of an Item is declared in the type
header, as well as the payload
size in length
. See Serialization Format for a list of common Item headers.
The headers described in this section are in addition to the common headers.
Event
Item type "event"
. This Item contains an error or default event payload
encoded in JSON.
Constraints:
- This Item may occur at most once per Envelope.
- This Item is mutually exclusive with
"transaction"
Items.
Envelope Headers:
event_id
- UUID String, required. Corresponds to the
event_id
field of the event payload. Clients are required to generate an event identifier ahead of time and set it at least in the Envelope headers. If the identifier mismatches between the Envelope and payload, the Envelope header takes precedence.
Additional Item Headers:
None
Transaction
Item type "transaction"
. This Item contains a transaction payload encoded
in JSON.
Constraints:
- This Item may occur at most once per Envelope.
- This Item is mutually exclusive with
"event"
Items.
Envelope Headers:
event_id
- UUID String, required. Corresponds to the
event_id
field of the transaction payload. Clients are required to generate an event identifier ahead of time and set it at least in the Envelope headers. If the identifier mismatches between the Envelope and payload, the Envelope header takes precedence.
Additional Item Headers:
None
Attachment
Item type "attachment"
. This Item contains a raw payload of an attachment
file. It is always associated to an event or transaction.
Constraints:
- This Item may occur multiple times per Envelope.
- For minidump and apple crash report attachments, the corresponding
"event"
Item must be sent within the same Envelope. - Generic attachments can be ingested separately from their events. We recommend sending them in the same Envelope, which allows for more efficient rate limiting and filtering.
- Generic attachments sent in separate Envelopes can be dropped independently of an event. To ensure consistent handling, consider sending them in the same request.
- The Sentry server supports special attachments to ingest event payloads for backwards compatibility. These are not part of the official public API and the behavior should not be relied upon.
Envelope Headers:
event_id
- UUID String, required. The identifier of the event or transaction.
Additional Item Headers:
filename
- String, required. The name of the uploaded file without a path component.
attachment_type
- String, optional. The special type of this attachment. Possible values are:
event.attachment
(default): A standard attachment without special meaning.event.minidump
: A minidump file that creates an error event and is symbolicated. The file should start with theMDMP
magic bytes.event.applecrashreport
: An Apple crash report file that creates an error event and is symbolicated.unreal.context
: An XML file containing UE4 crash meta data. During event ingestion, event contexts and extra fields are extracted from this file.unreal.logs
: A plain-text log file obtained from UE4 crashes. During event ingestion, the last logs are extracted into event breadcrumbs.
content_type
- String, optional. The content type of the attachment payload. Any MIME type may be used; the default is
application/octet-stream
.
Session
Item type "session"
contains a single session initialization or update to an
existing session for Release Health.
See the sessions documentation for the payload details.
Constraints:
- This Item may occur multiple times per Envelope.
- Ingestion may limit the maximum number of Items per Envelope, see Ingestion.
Additional Item Headers:
None
Sessions
Item type "sessions"
contains buckets of pre-aggregated session counts.
See the sessions documentation for the payload details.
Constraints:
- This Item may occur multiple times per Envelope.
- Ingestion may limit the maximum number of Items per Envelope, see Ingestion.
Additional Item Headers:
None
User Feedback
User Feedback was called User Report in the beginning. Therefore the envelope item type is "user_report"
.
The item contains a user feedback / user report JSON payload:
{"event_id":"9ec79c33ec9942ab8353589fcb2e04dc","email":"john@me.com","name":"John Me","comments":"It broke."}\n
Attributes
event_id
- UUID String, required. The identifier of the event or transaction.
email
- String, recommended. The email of the user.
name
- String, recommended. The name of the user.
comments
- String, recommended. Comments of the user about what happened.
Constraints:
- This Item may occur once per Envelope.
- User Feedbacks / Reports can be ingested separately from their events. We recommended to send them in the same Envelope.
Envelope Headers:
event_id
- UUID String, required. The identifier of the event or transaction.
Additional Item Headers:
None
Client Report
Item type "client_report"
contains a client report payload encoded in JSON.
See the client reports documentation for the payload details.
Constraints:
- This Item may occur multiple times per Envelope, but please avoid sending more client reports than necessary.
- This Item can either be included in an Envelope with other Items, or it may be sent by itself.
Envelope Headers:
None
Additional Item Headers:
None
Reserved Types
Reserved types may not be written by any implementation. They are reserved for future or internal use. This is the exhaustive list of reserved Item types:
security
unreal_report
form_data
Ingestion
This section describes how to ingest Envelopes into Relay or Sentry. The main ingestion endpoint for Envelopes is:
POST /api/<project_id>/envelope/
HTTP Headers
Envelope requests may contain all headers as regular store requests. The only
accepted content-type
is application/x-sentry-envelope
, which is implied if
it is missing. To minimize the necessity for CORS
preflights it's
acceptable to send text/plain
, multipart/form-data
and
application/x-www-form-urlencoded
as well. In either of those cases the
behavior however is the same as using application/x-sentry-envelope
.
Authentication
In addition to regular HTTP header- and querystring authentication, the Envelope
endpoint allows to authenticate via an Envelope header. To choose this
authentication method, set the "dsn"
Envelope header to the full DSN string.
If multiple forms of authentication are given, the endpoint validates that the
information matches and otherwise rejects the request. If both are missing, the
Envelope is rejected with status code 403 Forbidden
.
Backward Compatibility
Envelope header authentication requires Relay v21.6.0. Earlier versions of Relay do not support Envelope header authentication and respond with HTTP error 401 Unauthorized ("missing authorization information") to envelope uploads.
SDKs should not rely on Envelope header authentication to retain backward compatibility with older versions of Sentry on-premise unless absolutely required. Instead, stick to HTTP headers or query parameters wherever possible.
Size Limits
Event ingestion imposes limits on the size and number of Items in Envelopes. These limits are subject to future change and defined currently as:
- 20MB for a compressed Envelope request
- 100MB for a full Envelope after decompression
- 100MB for all attachments combined
- 100MB for each attachment Item
- 1MB for event and transaction Items
- 100 sessions per Envelope
- 100 pre-aggregated session buckets per each
"sessions"
Item