SDK
After this page your app reports every send and simulation attempt to WireTap, which unlocks the two failure classes on-chain watching cannot see: drops and preflight failures.
Watching the chain answers “why did this landed transaction fail?” — but a transaction that
never landed left no record anywhere. The SDK fixes that by capturing a small envelope at send
time (signature, blockhash validity window, RPC endpoint hash, wallet adapter, simulation
logs on failure). WireTap’s correlation job then matches envelopes against observed chain
data and classifies everything that never landed. This also powers the per-provider drop rates
behind provider_report.
Privacy: the SDK never sees keys or signing material. Payer addresses can be reported
as-is or as a salted hash (privacy: "hash").
Install
Section titled “Install”pnpm add @wiretap-labs/sdknpm install @wiretap-labs/sdkThe SDK is published on npm as @wiretap-labs/sdk.
Wrap your connection
Section titled “Wrap your connection”import { Connection } from "@solana/web3.js";import { createWireTap } from "@wiretap-labs/sdk";
const wiretap = createWireTap({ ingestUrl: process.env.WIRETAP_API_URL!, // your API base (hosted or self-hosted) apiKey: process.env.WIRETAP_API_KEY!, // ingest-scoped key (dashboard / wiretap init) program: "DemoAMM…", // program(s) you're tracking});
// wrap the connection you already use — send/simulate calls are observedconst connection = wiretap.wrapConnection( new Connection("https://api.devnet.solana.com"),);
// use `connection` exactly as before# auto-wire the SDK into ./src (rewrites `new Connection(...)`, shows a diff first)npx @wiretap-labs/cli init --sdkwrapConnection wraps sendRawTransaction, sendTransaction, and simulateTransaction.
(createWireTap also returns wrapKitSender, anchorProvider, and capturePreflightFailure
for Kit/Anchor code paths.) Envelopes are batched, sent asynchronously, and never block or
fail your sends — if the ingest endpoint is unreachable, batches are dropped after a bounded
retry.
See a drop get classified
Section titled “See a drop get classified”Any send through the wrapped connection is captured. If a transaction never lands — e.g. it went out on an already-stale blockhash — there’s no on-chain record, so the correlation job is what classifies it as a drop:
// `connection` is the wrapped connection from aboveconst sig = await connection.sendRawTransaction(staleTx.serialize());console.log(sig); // feed this to `/why` once it's classifiedWithin about a minute (one blockhash validity window plus the correlation interval), the drop is classified. Ask in Telegram or MCP:
/why <printed-signature>→ ✗ never landed — expired_blockhash sent 14:02:11 via rpc "public" · lastValidBlockHeight passed at 14:03:04 53 slots of lag between send and expiry — see /status for provider splitConfiguration
Section titled “Configuration”| Option | Default | Notes |
|---|---|---|
ingestUrl |
— | Required. Your WireTap API base (hosted or self-hosted) |
apiKey |
— | Required. Ingest-scoped key |
program |
— | Required. Program ID to attribute envelopes to |
payerPrivacy |
"plain" |
"hash" reports a salted hash of the payer |
flushIntervalMs |
3000 |
Envelope batch interval (ms) |
maxBatch |
50 |
Flush immediately once this many envelopes queue |
The RPC endpoint is reported as a hash + coarse label (helius, quicknode, public…) —
never the full URL, which may embed API keys.