The Netcode SDK catalog in the FirstByte console has two tables. The Package catalog table lists the engine-side packages (install command, version, channel, per-platform support, status). The Native plugins table lists the binaries those packages load — one row per build target. This page covers the second table: what each column is telling you, where the artifact belongs in a Unity project, and the exact guarantee each chip in the first table carries.

What ships as a native plugin

Every binding in the catalog is a thin layer over the same C wire core, exposed through the FFI header (clutchcall_moqt_ffi.h) that ships with the package. The engine package gives you the Unity-facing transport surface; the native plugin is the QUIC + MoQT implementation underneath it. The KPI strip shows the core version currently published alongside the packages (Wire core · FFI), and the Native targets KPI is just the row count of the Native plugins table. The Native plugins table has these columns: The Native plugins button in the page header downloads the set. If you install via UPM, the package already carries the binaries for the platforms its matrix row marks as supported — you only place artifacts by hand when you pull them separately, or when you vendor a single target into an existing plugin folder.

Where each artifact goes in a Unity project

Unity decides how to import a native binary from its location and from the import settings on its .meta file. Place the file from the Artifact column under Assets/Plugins/ in the directory for its target, then open the Plugin Inspector and confirm the platform and CPU selection matches the ABI column: Two rules that cause most of the support traffic:
  • Set the platform on the .meta, not just the folder. A binary left with “Any Platform” selected can be included twice, or included on a target it was not built for, and the failure surfaces only in the player build.
  • Keep the header next to the binary from the same release. The clutchcall_moqt_ffi.h in the package and the binary in the Native plugins table are versioned together. See Pinning the FFI core version.

Picking the right ABI

The ABI column is the authoritative list of architectures inside each artifact. Match it against the architecture your player is built for, not against your development machine:
  • Editor vs player. The editor loads the desktop artifact for the machine you are running on. An Apple-silicon editor needs an arm64 slice even when you only ship x86_64 players; a single-slice binary will work in one and fail in the other.
  • Android. The ABIs you ship must cover the “Target Architectures” set in Player Settings. If Player Settings includes an ABI with no matching .so under Assets/Plugins/Android/libs/, the store build still succeeds and the app fails on that device class only.
  • iOS. Device and simulator are different slices. If the artifact you were given does not list a simulator slice, build to a device.
  • WebGL. There is no ABI choice; the native side is linked in by the Emscripten toolchain. The toolchain version has to match the one your Unity version ships with.

What an ABI mismatch looks like at runtime

A mismatch never shows up as a compile error. The symptoms, in order of how often they are reported: When you hit the second row, treat it as a version problem rather than a placement problem: re-pull both the header and the binary from the same catalog row.

Signing and notarisation per platform

The Signing cell on each Native plugins row records the requirement for that target. Read the cell as the source of truth for the artifact you downloaded; what follows is how the requirement is usually satisfied in a Unity pipeline.
  • macOS. A native plugin inside an app bundle is signed as part of signing the app. If you enable the hardened runtime and notarise the build, the plugin has to carry your signature too — re-sign the bundle after Unity copies it in, then notarise the app as a whole. An unsigned or stale-signed plugin is the usual reason a notarised build launches and then fails on first connect.
  • iOS. Signing is handled by Xcode as part of signing the app. Static artifacts inherit the app signature; if you were given a framework instead, it must be embedded and signed, not merely linked.
  • Android. The .so files are not signed individually; the APK or AAB signature covers them. Do not strip or re-compress them after the Gradle step.
  • Windows. Authenticode signing of the plugin is separate from signing your installer. Sign the plugin if your distribution channel checks per-file signatures.
  • Linux. No platform signing step.
  • WebGL. Nothing to sign; the code is linked into the wasm module and is covered by however you serve and integrity-check your build output.
Whatever the platform, sign after Unity has finished writing the player output. Post-build steps that copy plugins around invalidate signatures made earlier in the pipeline.

Release channels and status chips

The two chips in the Package catalog table describe different things and are counted separately in the KPI strip. What they do not tell you:
  • A channel is not a compatibility contract across versions. The chip describes the release track of the row, not a promise that the next version on the same track keeps the same API surface. The number to reason about for compatibility is the version pair in the next section.
  • A channel says nothing about the platform cells beside it. Channel and the per-platform matrix are independent columns; a stable row can still show reduced support for an individual platform.
  • live is a catalog state, not a maturity level. A row can be live on a non-stable channel. Read both chips before you pin a version into a shipping build.
Only the live rows get an install card below the table, with the exact install command and the row’s note. Copy the command from the card rather than typing a package name from the table — the pkg line in the table is the package identifier, not the full command.

The platform support matrix

The six columns after Channel in the Package catalog table are the build targets: Win, macOS, Linux, Android, iOS, WebGL. Each cell shows that binding’s support for that target. The matrix is per binding; the Native plugins table below it is per artifact. Use them together:
  1. Find your binding’s row and check the cell for your target platform.
  2. Find the matching Platform row in the Native plugins table for the artifact name, ABI, signing requirement, and size.
If a target is supported in the matrix but you cannot find a row for it in the Native plugins table, the binding does not load a separate binary on that target — WebGL being the usual case, where the native side is linked in at build time.

Pinning the FFI core version alongside the package version

There are two versions in play, and the console shows both:
  • the package version, in the Version column of the Package catalog row;
  • the FFI core version, in the Wire core KPI at the top of the screen.
They move independently. A package update can carry a different core, and the header that your native code compiles against comes from the package. For reproducible builds, pin the package exactly in the project manifest rather than letting UPM resolve a range:
Then record the core version from the Wire core KPI in the same commit — in a lockfile comment, a build note, or your own manifest — so that a later EntryPointNotFoundException can be traced to a core bump rather than to a placement mistake. If you vendor binaries by hand instead of installing through UPM, take the header and every platform artifact from a single download so that all of them carry the same core.
  • Telemetry — the transport-level metrics and traces the core emits
  • Authentication — relay tokens and the namespace scope the transport presents on connect