# Falcon telemetry (/falcon/telemetry)

> Instrument Falcon Solana submissions so acceptance and landing stay separate metrics, per transport, without ever logging your API key.



Falcon's response tells you almost nothing about whether a transaction landed, and each transport tells you a different amount. So instrument for that: one record for what Falcon said, one record for what the chain did, joined on the signature.

## What to measure

Since no HTTP route reports a forwarding failure, a `200` rate near 100% is the expected steady state rather than a health signal. The number that means something is your **landing rate**, measured on your Solana RPC.

| Metric                    | Source                                               | What a drop means                                               |
| ------------------------- | ---------------------------------------------------- | --------------------------------------------------------------- |
| Acceptance rate           | Falcon response per transport                        | Your requests are malformed, unauthorized or over the allowance |
| Landing rate              | `getSignatureStatuses` on your RPC                   | Competition, tip level, blockhash expiry, or delivery loss      |
| Time to first observation | Submit timestamp → first status                      | Regional or pacing problems                                     |
| Expiry rate               | Signatures that never landed before blockhash expiry | You are retrying past the useful window                         |

Track them separately per transport and per region, or you'll average away the one transport that's failing.

## What each transport can tell you

| Transport               | Record                                                                                                  | Structurally unavailable                                                                                |
| ----------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| JSON-RPC                | HTTP status, JSON-RPC `code`, message prefix, `data.minimumLamports` / `data.expected` / `data.actual`  | Forwarding outcome                                                                                      |
| `/binary`, `/plaintext` | HTTP status **and** the plain-text body                                                                 | Forwarding outcome; the body is the only way to separate two different `413`s or seven different `400`s |
| QUIC                    | Whether the error was a `SubmitError` or a transport error, the variant, and the active `TransportMode` | Forwarding outcome; in datagram mode, acceptance too                                                    |
| Native UDP              | Local `send()` errors only                                                                              | Everything else: acceptance, rejection reason, rate limiting                                            |

Record the active `TransportMode` alongside every QUIC result. In stream mode `Ok(())` covers both "the server accepted it" and "the datagram was queued and the ack got lost", and without the mode those merge into one number.

## Fields worth recording per submission

Key everything on the **transaction signature**: you know it before you submit, on every transport.

| Field                                                                    | Why                                                                                                                                                |
| ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| Signature                                                                | The only identifier that exists on all five transports                                                                                             |
| Transport and region                                                     | Failures are usually specific to one                                                                                                               |
| Serialized size in bytes                                                 | Proximity to the 1,232-byte cap explains `TooLarge` clusters                                                                                       |
| Submit timestamp (UTC)                                                   | Joins to slot timing and to support requests                                                                                                       |
| `skipPreflight` value                                                    | Preflight failures (`-32002`, `-32603`) only exist when it is `false`                                                                              |
| Falcon result: status, code and message prefix, or `SubmitError` variant | The whole error surface                                                                                                                            |
| Attempt number for this signature                                        | Falcon suppresses a duplicate once that signature has been delivered, so attempts are not independently observable server-side; count them locally |
| Landing state, slot, and time from submit                                | The metric that matters                                                                                                                            |
| Terminal reason: landed, expired, abandoned                              | Closes the record                                                                                                                                  |

Match Falcon errors on **status + code + message prefix**, never on full-string equality; messages carry variable detail like `parse error: <detail>` and the simulation error text.

## A pcap of Falcon UDP traffic is a credential dump

The first 16 bytes of every native UDP datagram are your raw API key, or 36 ASCII characters in the alternative frame. The same goes for any HTTP access log that keeps the query string, since the key travels as `?api-key=`.

So don't record:

* the API key, in any transport;
* full request URLs: strip or hash the `api-key` parameter before the URL reaches a log, a trace or an error reporter;
* packet captures of UDP or QUIC traffic that leave your environment;
* the client certificate material `falcon-client` generates at connect time.

## Reporting a problem

On [Discord](https://discord.gg/corvus-labs), include:

* the transaction signature;
* UTC timestamp and the affected time window;
* region and transport;
* the exact error: HTTP status + JSON-RPC code + message, the plain-text body, or the `SubmitError` variant;
* attempt count for that signature;
* what your Solana RPC reports for the signature, if anything.

Never post the API key, or a URL containing it. For UDP problems, reproduce the same transaction over JSON-RPC first; it turns the silence into a readable error.

## Related

* [Falcon errors & retries](/falcon/errors)
* [Falcon native UDP](/falcon/udp)
* [Falcon regions & endpoints](/falcon/regions)
