Features Solutions Technology Tokenomics Docs About Launch App
Docs / Tutorials / Product Tagging

Product Tagging Tutorial

How a physical product becomes a TAG IT digital twin — the parts you can run today, and the parts that are permissioned.

Read This First

TAG IT contracts are deployed to Base Sepolia testnet (chainId 84532) only. There is no mainnet deployment, and the contracts are not audited. Every lifecycle write — mint, bindTag, activate, claim — is gated by a BIDGES capability badge on the calling address. There is no public API, no self-serve endpoint and no SDK method that registers a product. The read and verification steps in Step 6 are open to everyone and work today.

Tutorial Overview

This tutorial follows a single physical product from a blank NFC tag to a readable on-chain record. The physical work — selecting, personalizing and attaching the tag — is yours. The on-chain lifecycle transitions are executed by an address that holds the matching capability badge. The verification step at the end requires nothing but an RPC endpoint.

What Is Actually Available

Stage Mechanism Who can do it today
Select and attach an NTAG 424 DNA tag Physical work, no software Anyone
Personalize the chip (AES keys, SDM mirroring) PC/SC personalization tooling Not publicly available — see Step 3
Lifecycle writes on TAGITCore (mint, bindTag, activate, claim) Direct contract calls on Base Sepolia Capability-badge holders only
Read an asset's owner and lifecycle state getAsset(uint256) via any Base Sepolia RPC Anyone — verified working
Verify a physical tap verify.tagit.network Anyone holding the physical tag

Prerequisites

There Is No SDK for This Workflow

The @tagit/sdk package is not published to npm — installing it fails with a 404. It is TypeScript-only; there is no Python, Swift or Kotlin package. Its scope is agent identity, reputation and validation, plus WTag and Voucher helpers — it contains no product registration, tag encoding, verification or ownership-transfer functions. Everything on this page is done with a plain Ethereum client (viem, ethers or cast) or with physical tooling.

Estimated Time

The physical steps take roughly 30-45 minutes. The on-chain steps depend on badge issuance, which is a manual process today.

Step 1: Prepare Your Product

Before attaching an NFC tag, you need to identify the optimal placement location and prepare the surface.

Tag Placement Considerations

Placement Guidance

Place tags in accessible but protected areas. For luxury goods, common locations include inside packaging, on product labels, or embedded within the product itself.

Choose a location that is:

Surface Preparation

  1. Clean the surface with isopropyl alcohol to remove dust, oil, and debris
  2. Allow the surface to dry completely (2-3 minutes)
  3. For porous materials, apply a thin primer coat if necessary
  4. Mark the exact placement location with a light pencil mark
Important

Never place NFC tags directly on or within 1cm of metal surfaces. Use ferrite shielding if metal placement is unavoidable.

Step 2: Select NFC Tag

Choosing the right NFC tag is crucial for security and durability. TAG IT Network standardizes on tags with hardware cryptographic authentication — the NTAG 424 DNA is the chip for all item-level tagging.

Recommended Tags

Tag Type Security Level Best For
NTAG 424 DNA High (AES-128) All item-level tagging (TAG IT standard)
ICODE SLIX2 Medium Package and logistics layer

Note: NTAG 213/215/216 tags are legacy — not supported by TAG IT. They have no on-chip encryption and cannot be bound to an asset.

For detailed tag specifications and purchasing options, see our Chip Selection Guide.

Step 3: Personalize the Tag

A blank NTAG 424 DNA is not yet a TAG IT tag. It first has to be personalized: its AES-128 key set is written, and Secure Dynamic Messaging (SDM) is configured so that every tap emits a freshly encrypted PICC data block and a CMAC over it.

Those two values are what the verifier consumes. A personalized tag produces a request of this shape when tapped:

GET https://verify.tagit.network/api/verify?picc=<32 hex chars>&cmac=<16 hex chars>

The picc and cmac values are generated by the chip's on-board AES engine at tap time and change on every tap. Software cannot produce a valid pair without the chip's secret keys, which is the entire point of using this chip. Chip-level detail lives in the Encoding Guide.

Programmatic Encoding — Not Publicly Available

No Public Encoder

TAG IT does not publish a tag-personalization app or library. There is no TAG IT encoder listing on the App Store or Google Play, and no npm package that writes keys to a chip. Personalization is currently performed in-house with an ACR1252U-class PC/SC contactless reader driven by the internal TAG IT console, because it involves provisioning secret AES keys. If you need tags personalized for a pilot, contact info@tagit.network — self-serve personalization does not exist yet.

Tip

Always test a personalized tag with a smartphone before attaching it to the product. Once a tag is locked and attached, re-personalizing it may be impossible.

Step 4: The On-Chain Lifecycle

A TAG IT asset moves through a seven-state machine on TAGITCore, deployed at 0x3aDc7EFDb58Ae85483eFf5D4966D916185f31d1D on Base Sepolia. Tagging a product means walking the first four transitions.

Transition Function Required capability
NONE (0) → MINTED (1) mint(address to, bytes32 metadata) keccak256("MINTER")
MINTED (1) → BOUND (2) bindTag(uint256, bytes32, bytes, bytes) keccak256("BINDER")
BOUND (2) → ACTIVATED (3) activate(uint256 tokenId) keccak256("ACTIVATOR")
ACTIVATED (3) → CLAIMED (4) claim(uint256 tokenId, address newOwner) keccak256("CLAIMER")

Permissioned Write Functions — You Cannot Call These

The signatures below are the real functions on TAGITCore. They are shown so you can read the ABI and understand the flow. Every one of them reverts unless the caller holds the matching BIDGES capability badge, so this block is reference material, not a snippet you can run.

// TAGITCore, Base Sepolia (chainId 84532)
// 0x3aDc7EFDb58Ae85483eFf5D4966D916185f31d1D
// Each function carries requiresCapability(...) — reverts without the badge.

// NONE -> MINTED. metadata is a 32-byte metadata identifier (e.g. an IPFS digest).
function mint(address to, bytes32 metadata)
    external
    returns (uint256 tokenId);

// MINTED -> BOUND. Binds one personalized chip to one token, permanently.
function bindTag(
    uint256 tokenId,
    bytes32 tagHash,
    bytes calldata challengeResponse,
    bytes calldata oracleSignature
) external;

// BOUND -> ACTIVATED. QA sign-off; the asset is now sellable.
function activate(uint256 tokenId) external;

// ACTIVATED -> CLAIMED. Hands the asset to its end owner.
function claim(uint256 tokenId, address newOwner) external;

Why bindTag Needs Four Arguments

bindTag is the step that makes counterfeiting hard, so it is the step with the most checks:

In other words, a token cannot be bound to a chip that was never physically scanned by an attested reader — not even by a badge holder.

No Registration API

There is no REST endpoint, hosted service or SDK call that performs any of these writes on your behalf. Onboarding a manufacturer today means issuing capability badges to their address on Base Sepolia and having them submit transactions directly. Gas is paid in Base Sepolia testnet ETH, available from the Base Sepolia faucet.

Later States

Beyond CLAIMED, the state machine continues: flag (CLAIMED → FLAGGED, capability keccak256("FLAGGER")), resolve (FLAGGED → CLAIMED, keccak256("RESOLVER")) and recycle (→ RECYCLED, keccak256("RECYCLER")). One function is not capability-gated: transferAsset(uint256 tokenId, address to) is owner-gated, so the current owner of a CLAIMED asset can resell it themselves. See the Ownership Transfer tutorial.

Step 5: Attach the Tag

With the tag personalized, attach it to the product. Binding on-chain can happen before or after attachment — what matters is that the chip can still be scanned. Do not attach a tag you have not read-tested.

Application Methods

Adhesive Application (Most Common)

  1. Peel the backing from the adhesive NFC tag
  2. Align the tag with your marked placement location
  3. Press firmly from the center outward to remove air bubbles
  4. Apply pressure for 30 seconds for optimal adhesion
  5. For added security, apply a tamper-evident overlay sticker

Heat-Sealed Tags

For textile and apparel applications:

  1. Position the heat-seal tag on the fabric
  2. Apply heat press at 150-170°C for 10-15 seconds
  3. Allow to cool before handling

Sewn-In Labels

For garments and accessories:

Embedded Tags

For products with internal cavities:

Step 6: Verify — This Part Runs Today

Reading an asset needs no badge, no API key and no account. Point any Base Sepolia RPC at TAGITCore and call getAsset.

Read Asset State with viem

// npm install viem
import { createPublicClient, http } from 'viem';
import { baseSepolia } from 'viem/chains';

const TAGIT_CORE = '0x3aDc7EFDb58Ae85483eFf5D4966D916185f31d1D';

const getAssetAbi = [{
  type: 'function',
  name: 'getAsset',
  stateMutability: 'view',
  inputs: [{ name: 'tokenId', type: 'uint256' }],
  outputs: [
    { name: 'assetOwner', type: 'address' },
    { name: 'timestamp',  type: 'uint64'  },
    { name: 'state',      type: 'uint8'   },
    { name: 'flags',      type: 'uint8'   },
    { name: 'reserved',   type: 'uint16'  }
  ]
}];

const client = createPublicClient({
  chain: baseSepolia,                          // chainId 84532
  transport: http('https://sepolia.base.org')
});

const [assetOwner, timestamp, state] = await client.readContract({
  address: TAGIT_CORE,
  abi: getAssetAbi,
  functionName: 'getAsset',
  args: [50n]
});

console.log({ assetOwner, timestamp, state });

Actual Output

Run against token 50 on Base Sepolia:

{
  assetOwner: '0x458B4d0c3a55006965Fd13D6af7B8509De51Cb3D',
  timestamp: 1784246184n,
  state: 4
}

state: 4 is CLAIMED, and timestamp is the Unix time of the last state change — 1784246184 is 2026-07-16T23:56:24Z. The same call with Foundry:

cast call 0x3aDc7EFDb58Ae85483eFf5D4966D916185f31d1D \
  "getAsset(uint256)(address,uint64,uint8,uint8,uint16)" 50 \
  --rpc-url https://sepolia.base.org

Lifecycle State Values

Value State Meaning
0NONEToken does not exist
1MINTEDDigital twin created, no chip bound
2BOUNDChip cryptographically bound to the token
3ACTIVATEDQA passed, ready for market
4CLAIMEDHeld by an end owner
5FLAGGEDLost, stolen or under investigation
6RECYCLEDEnd of life, terminal

Two other public reads are useful here: getTokenByTag(bytes32 tagHash) returns the token bound to a chip (0 if unbound), and totalSupply() returns the number of digital twins minted.

Human-Readable Verification Pages

These routes render a verification page in a browser, all on the public host verify.tagit.network:

Corrected URL Format

An earlier revision of this page showed https://verify.tagit.network/{tagId}. That route does not exist and returns 404. Use /asset/{tokenId} or /tag/{uid}.

Tap-Backed Verification Endpoints

These two endpoints consume the SDM values a genuine tap produces. They are not callable with invented parameters — that is the security property, not a limitation:

GET https://verify.tagit.network/api/verify?picc=<32 hex>&cmac=<16 hex>

GET https://verify.tagit.network/api/dpp/01/<GTIN>/21/<serial>?picc=<32 hex>&cmac=<16 hex>

The second returns a W3C Verifiable Credential digital product passport for the scanned item.

Verification API Health

The verification API exposes an unauthenticated health check:

curl -s https://api.tagit.network/health
# 200 → {"status":"ok", ...}

The machine verification endpoint is metered with the x402 payment protocol. Calling it without payment returns a 402 carrying the payment envelope, which is the expected first half of the handshake:

curl -s -o /dev/null -w '%{http_code}\n' \
  -X POST https://api.tagit.network/verify
# 402

Installation Checklist

  1. Read test: tap the tag with a phone — the verification page should load.
  2. Range test: read from several angles; NTAG 424 DNA typically works within 2-4cm.
  3. State test: call getAsset(tokenId) and confirm the state is what you expect (2 = BOUND after binding, 3 = ACTIVATED after QA).
  4. Binding test: call getTokenByTag(tagHash) and confirm it returns your token ID rather than 0.

Best Practices

Durability

Placement

Security

Batch Operations

TAGITCore has batch equivalents for high-volume lines. They carry the same capability gating as their single-item counterparts, so the same "you cannot call these without a badge" caveat applies.

// Capability-gated. MAX_BATCH_SIZE = 100 — larger calls revert with
// BatchTooLarge, mismatched array lengths revert with ArrayLengthMismatch.

function batchMint(address[] calldata recipients, bytes32[] calldata metadata)
    external
    returns (uint256[] memory tokenIds);

function batchBind(
    uint256[] calldata tokenIds,
    bytes32[] calldata tagHashes,
    bytes[] calldata challengeResponses,
    bytes calldata oracleSignature
) external;

function batchActivate(uint256[] calldata tokenIds) external;
Where This Leaves You

You can physically tag a product today, and you can read and verify any asset that already exists on Base Sepolia. Getting your own assets on-chain currently requires TAG IT to issue capability badges to your address — that step is manual, and testnet-only, until the contracts are audited and mainnet is live.

Next Steps

Edit this page on GitHub
Type to search documentation...