Lunar Shadow Labs

Raw Yellowstone gRPC vs a decoded WebSocket

Yellowstone (Geyser) gRPC gives you raw Solana transactions as fast as a node sees them. Turning those into "this wallet bought this token on this pool for this much" is a separate job. This guide lists what that job involves, and when doing it yourself makes more sense than using a decoded feed like ours.

What decoding involves

Our origin subscribes to Yellowstone gRPC for the programs we cover and does the following for every transaction. If you parse raw gRPC yourself, this is your list:

The result: one JSON shape

A PumpSwap trade and a Raydium CLMM trade arrive in the same shape. Here is one swap from our feed:

{
  "v": 1,
  "seq": 13619,
  "kind": "swap",
  "venue": "pumpswap",
  "keys": [
    "7XSrFStYppauv9dvrPBqMXqJarQJo4QFSDsUp7Dmpump",
    "So11111111111111111111111111111111111111112",
    "6tv1HzMFM93HHPZds7kyWZFuUEgVAnNkAgT1d5Dg7Gw5",
    "jMrze5nuUXTTWraMGWDnqzLED5JWvQygLByH86hpwJ1"
  ],
  "stage": "executed",
  "source": "geyser",
  "commitment": "processed",
  "slot": 454291681,
  "sig": "3AqTMkaFsKzWjn7BgzFyC2dZZYdS4wksvHB67VYBnt5KmU3GbKK2tfcTKAqrD7PoBqBL3AMJjKt79E3Jm7EaUVKW",
  "ix": 0,
  "inner": 26,
  "t_ingest_us": 1791394580178034,
  "t_emit_us": 1791394580178087,
  "via": "DF1ow4tspfHX9JwWJsAb9epbkA8hmpSEAtxXy1V27QBH",
  "pool": "6tv1HzMFM93HHPZds7kyWZFuUEgVAnNkAgT1d5Dg7Gw5",
  "user": "jMrze5nuUXTTWraMGWDnqzLED5JWvQygLByH86hpwJ1",
  "base_mint": "7XSrFStYppauv9dvrPBqMXqJarQJo4QFSDsUp7Dmpump",
  "quote_mint": "So11111111111111111111111111111111111111112",
  "is_buy": true,
  "base_amount": "328124895560",
  "quote_amount": "210414078",
  "base_decimals": 6,
  "quote_decimals": 9,
  "price": 6.412621561094693e-07,
  "fees": {
    "lp": "415839",
    "protocol": "103960",
    "coin_creator": "1975231",
    "cashback": "0",
    "buyback": "51980",
    "holder_rewards": "1975231"
  },
  "partial": false,
  "derived": false,
  "base_flags": {
    "program": "token2022",
    "decimals": 6,
    "supply": "960096786441637",
    "mint_authority": null,
    "freeze_authority": null,
    "metadata_pointer": "7XSrFStYppauv9dvrPBqMXqJarQJo4QFSDsUp7Dmpump",
    "extensions": [
      18,
      19
    ]
  },
  "quote_flags": null,
  "x": {
    "pool_quote_amount_in": "207919048",
    "pool_quote_amount_in_with_lp_fee": "208334887",
    "pool_base_token_reserves": "167125465510533",
    "pool_quote_token_reserves": "88191182513",
    "virtual_quote_reserves": "17501328902",
    "ix_name": "buy"
  }
}

Captured from our live feed on 2026-10-07.

The same fields (pool, user, base_mint, quote_mint, is_buy, amounts, decimals, price, fees) appear for every venue; venue-specific extras go in x.

import asyncio, json, os, websockets   # pip install websockets

URL = "wss://feed.lunarshadowlabs.com/ws?kinds=swap"
HEADERS = {"Authorization": f"Bearer {os.environ['LSL_KEY']}"}

async def main():
    async with websockets.connect(URL, additional_headers=HEADERS, max_size=None) as ws:
        async for raw in ws:
            m = json.loads(raw)
            if m["kind"] == "swap":
                print(m["venue"], "buy" if m["is_buy"] else "sell", m["base_mint"], m["price"])

asyncio.run(main())

When to parse raw gRPC yourself

When a decoded feed is simpler

Latency and uptime as we observe them are published on our status page.

Try the feed

One WebSocket, 12 Solana venues, one flat price.

Start free trial Read the docs

3-day free trial, then $49/month per license plus applicable tax, charged automatically every month until you cancel. Cancel online any time before the trial ends and you pay nothing. Starting a trial means you agree to the Terms. Market data only, no signals or advice.

← All guides