---
title: "LoRaWAN payload decoder tester for TTN and ChirpStack"
canonical: https://wavect.io/tools/lorawan-payload-codec-tester/
language: en
description: "Test LoRaWAN JavaScript payload decoders and encoders for The Things Stack and ChirpStack. Run hex or Base64 fixtures locally and export automated tests."
image: "https://wavect.io/img/general/bak/open_graph_preview.jpg"
---

BROWSER-LOCAL LORAWAN WORKBENCH

# Test the codec before the next sensor packet becomes a production mystery.

Paste the JavaScript you actually deploy, add real byte payloads and expected JSON, then run the whole fixture set in an isolated local sandbox. Modern TTN and ChirpStack functions and legacy Decoder or Encoder formats are supported.

[Open the workbench](#tool-app) [View source](https://github.com/wavect/lorawan-payload-codec-tester)

- Profiles TTN v3 · ChirpStack v4 · legacy
- Price Free · open source
- Execution Isolated in your browser
- Output Fixtures · tests · report

**PAYLOAD LAB**

FPORT 4 · UPLINK **temperature: -21.3°C**

Fixture matches expected output

THE USEFUL PART

This is a test harness, not a decoder catalogue. It runs your codec against your payloads, shows exactly which fixture failed, and turns the result into tests you can keep beside the device integration.

RUN THE REAL CODE

## Payload codec workbench

Start with a sample or paste a vendor codec. Each vector can exercise a different operation, fPort, payload encoding, variables, decoded input, and expected result.

Code and payloads stay local

**LoRaWAN codec lab** Disposable sandbox · deterministic fixtures

Modern uplinkNormalized payloadDownlink round tripLegacy DecoderInvalid return shapeHanging codec Load sample Run all

01

### Codec source

Compatibility profileThe Things Stack v3ChirpStack v4Legacy Decoder / Encoder

The sandbox exposes only the formatter input. Network, storage, imports, and page access are unavailable.

02

### Test vectors

03

### Results and exports

Run one vector or the complete set to see output, contract findings, byte reads, and expected-value differences.

Opaque-origin worker sandbox 1 second execution limit No upload or persistence

FROM VENDOR PDF TO REGRESSION TEST

## A codec workflow that survives the pilot

The same fixtures can be used while translating a vendor specification, migrating network servers, and reviewing later firmware changes.

1. 01 - **Paste the deployed formatter** - Use the exact JavaScript from the device profile, including helper functions and lookup tables.
2. 02 - **Add real packets and expectations** - Capture representative uplinks and downlinks, then state the complete JSON result you expect.
3. 03 - **Export a durable test** - Keep the generated fixtures and Vitest file with the integration so firmware or codec changes cannot silently reinterpret field data.

BUILT FROM FIELD WORK

## Useful when the fleet contains more than one happy-path device

Wavect wrote uplink decoders and downlink encoders while integrating multi-vendor hardware into a city-scale LoRaWAN platform. The expensive bugs were rarely syntax errors. They were quiet disagreements about bytes, ports, firmware variants, and output contracts.

### Both network-server conventions

Exercise modern The Things Stack and ChirpStack signatures or older Decoder and Encoder functions without creating an application first.

### Expected output, not visual optimism

A pretty JSON preview is not a test. Fixtures fail when the complete output differs from the value you declared.

### Artifacts that leave the browser

Export portable vectors, a runnable test file, or a Markdown report for a pull request and handover.

HONEST LIMITS

## What the workbench cannot prove

- It uses browser JavaScript semantics. Embedded runtime limits and engine-specific behavior still need a final test in the target network server.
- It reports an endian or signedness problem only when an expected result exposes the mismatch. It does not guess the vendor's intended byte order.
- It tests application payload formatters, not LoRaWAN encryption, radio coverage, join behavior, duty cycle, or gateway scheduling.
- A passing fixture set verifies the supplied cases. It is not proof that every firmware payload variant is covered.

## Questions about the codec tester

### Does the tool upload my codec or sensor payloads?

No. Code and fixtures are passed to a disposable browser worker inside an opaque-origin sandbox. They are not sent to Wavect or saved after the page is closed.

### Can it test both The Things Stack and ChirpStack codecs?

Yes. Their current JavaScript codec contracts use decodeUplink and encodeDownlink style functions. The tool also supports legacy Decoder and Encoder signatures used by older deployments.

### Can I test several firmware versions?

Yes. Create named vectors for each firmware and packet shape, or export separate fixture files when the codec itself differs.

### Will it tell me whether a temperature is little-endian?

Only when you provide an expected result. Several byte interpretations can be syntactically valid, so the tool does not invent device semantics that are absent from your fixture.

FREE · OPEN SOURCE · NO UPLOAD

## Turn the packet that failed today into the test that protects tomorrow.

Run the codec locally, export the fixtures, and keep the evidence with the integration.

[Return to the workbench](#tool-app) [View the source](https://github.com/wavect/lorawan-payload-codec-tester)

## Structured Data

```json
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@id": "https://wavect.io/#organization",
      "@type": [
        "Organization",
        "ProfessionalService",
        "LocalBusiness"
      ],
      "employee": [
        {
          "@id": "https://wavect.io/team/kevin-riedl/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Kevin Riedl",
          "url": "https://wavect.io/team/kevin-riedl/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        },
        {
          "@id": "https://wavect.io/team/christof-jori/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Christof Jori",
          "url": "https://wavect.io/team/christof-jori/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        }
      ],
      "founder": [
        {
          "@id": "https://wavect.io/team/kevin-riedl/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Kevin Riedl",
          "url": "https://wavect.io/team/kevin-riedl/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        },
        {
          "@id": "https://wavect.io/team/christof-jori/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Christof Jori",
          "url": "https://wavect.io/team/christof-jori/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        }
      ],
      "legalRepresentative": [
        {
          "@id": "https://wavect.io/team/kevin-riedl/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Kevin Riedl",
          "url": "https://wavect.io/team/kevin-riedl/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        },
        {
          "@id": "https://wavect.io/team/christof-jori/#person",
          "@type": "Person",
          "jobTitle": "Managing Director",
          "name": "Christof Jori",
          "url": "https://wavect.io/team/christof-jori/",
          "worksFor": {
            "@id": "https://wavect.io/#organization",
            "@type": [
              "Organization",
              "ProfessionalService",
              "LocalBusiness"
            ]
          }
        }
      ],
      "name": "Wavect GmbH",
      "subjectOf": {
        "@id": "https://wavect.io/verified-claims.json#dataset",
        "@type": "Dataset",
        "creator": {
          "@id": "https://wavect.io/#organization",
          "@type": [
            "Organization",
            "ProfessionalService",
            "LocalBusiness"
          ]
        },
        "description": "A machine-readable registry of quantitative and qualitative claims published by Wavect, with review dates, localized page appearances and public third-party citations where available.",
        "inLanguage": "en",
        "isAccessibleForFree": true,
        "license": "https://creativecommons.org/licenses/by/4.0/",
        "name": "Wavect verified publication claims",
        "url": "https://wavect.io/verified-claims.json"
      },
      "url": "https://wavect.io/"
    },
    {
      "@id": "https://wavect.io/team/kevin-riedl/#person",
      "@type": "Person",
      "jobTitle": "Managing Director",
      "name": "Kevin Riedl",
      "sameAs": [
        "https://www.wikidata.org/wiki/Q139796365",
        "https://www.linkedin.com/in/wsdt",
        "https://github.com/wsdt"
      ],
      "url": "https://wavect.io/team/kevin-riedl/",
      "worksFor": {
        "@id": "https://wavect.io/#organization",
        "@type": [
          "Organization",
          "ProfessionalService",
          "LocalBusiness"
        ]
      }
    },
    {
      "@id": "https://wavect.io/team/christof-jori/#person",
      "@type": "Person",
      "jobTitle": "Managing Director",
      "name": "Christof Jori",
      "sameAs": [
        "https://www.wikidata.org/wiki/Q139796367",
        "https://www.linkedin.com/in/jocr77/",
        "https://github.com/jo-chris"
      ],
      "url": "https://wavect.io/team/christof-jori/",
      "worksFor": {
        "@id": "https://wavect.io/#organization",
        "@type": [
          "Organization",
          "ProfessionalService",
          "LocalBusiness"
        ]
      }
    },
    {
      "@id": "https://wavect.io/#website",
      "@type": "WebSite",
      "inLanguage": [
        "en",
        "de",
        "es",
        "zh"
      ],
      "name": "Wavect",
      "potentialAction": {
        "@type": "SearchAction",
        "query-input": "required name=search_term_string",
        "target": {
          "@type": "EntryPoint",
          "urlTemplate": "https://wavect.io/search/?q={search_term_string}"
        }
      },
      "publisher": {
        "@id": "https://wavect.io/#organization",
        "@type": [
          "Organization",
          "ProfessionalService",
          "LocalBusiness"
        ]
      },
      "url": "https://wavect.io/"
    },
    {
      "@id": "https://wavect.io/tools/lorawan-payload-codec-tester/#webpage",
      "@type": "WebPage",
      "dateModified": "2026-08-05",
      "inLanguage": "en",
      "isPartOf": {
        "@id": "https://wavect.io/#website",
        "@type": "WebSite"
      },
      "lastReviewed": "2026-08-05",
      "url": "https://wavect.io/tools/lorawan-payload-codec-tester/"
    }
  ]
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "SoftwareApplication",
  "applicationCategory": "DeveloperApplication",
  "browserRequirements": "JavaScript, Web Workers, and sandboxed iframes",
  "codeRepository": "https://github.com/wavect/lorawan-payload-codec-tester",
  "description": "Test LoRaWAN JavaScript payload decoders and encoders for The Things Stack and ChirpStack. Run hex or Base64 fixtures locally and export automated tests.",
  "isAccessibleForFree": true,
  "name": "LoRaWAN Payload Codec Tester",
  "offers": {
    "@type": "Offer",
    "price": "0",
    "priceCurrency": "EUR"
  },
  "operatingSystem": "Any modern browser",
  "url": "https://wavect.io/tools/lorawan-payload-codec-tester/"
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "item": "https://wavect.io/",
      "name": "Home",
      "position": 1
    },
    {
      "@type": "ListItem",
      "item": "https://wavect.io/tools/",
      "name": "Small tools for jobs that should not stay annoying.",
      "position": 2
    },
    {
      "@type": "ListItem",
      "item": "https://wavect.io/tools/lorawan-payload-codec-tester/",
      "name": "LoRaWAN Payload Codec Tester",
      "position": 3
    }
  ]
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "No. Code and fixtures are passed to a disposable browser worker inside an opaque-origin sandbox. They are not sent to Wavect or saved after the page is closed."
      },
      "name": "Does the tool upload my codec or sensor payloads?"
    },
    {
      "@type": "Question",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Yes. Their current JavaScript codec contracts use decodeUplink and encodeDownlink style functions. The tool also supports legacy Decoder and Encoder signatures used by older deployments."
      },
      "name": "Can it test both The Things Stack and ChirpStack codecs?"
    },
    {
      "@type": "Question",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Yes. Create named vectors for each firmware and packet shape, or export separate fixture files when the codec itself differs."
      },
      "name": "Can I test several firmware versions?"
    },
    {
      "@type": "Question",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Only when you provide an expected result. Several byte interpretations can be syntactically valid, so the tool does not invent device semantics that are absent from your fixture."
      },
      "name": "Will it tell me whether a temperature is little-endian?"
    }
  ],
  "speakable": {
    "@type": "SpeakableSpecification",
    "cssSelector": [
      ".faq-question",
      ".faq-answer"
    ]
  }
}
```
