Utility Functions
Portal URL building, condition validation, and common helper functions.
Utility Functions
The smartlinks SDK includes utilities for common tasks like building portal URLs and validating conditional rendering logic.
See also: API Summary for the complete SDK reference.
Installation
import { utils } from '@proveanything/smartlinks'
Path Builder Utility
Builds full portal URLs by default. Pass in objects (collection, product, batch, etc.) and the function extracts what it needs. Uses collection.portalUrl as the domain, or defaults to https://zt.smartlinks.io.
Basic Usage
import { utils } from '@proveanything/smartlinks'
// Returns full URL by default (uses collection.portalUrl)
const url = utils.buildPortalPath({
collection: myCollection, // uses collection.portalUrl or default domain
product: myProduct // ownGtin is read from product, not overridden
})
// Returns: https://portal.smartlinks.io/c/abc123/prod123
// Return just the path (no domain)
const path = utils.buildPortalPath({
collection: { shortId: 'abc123' },
productId: 'prod1',
pathOnly: true // Set to true for path only
})
// Returns: /c/abc123/prod1
// Or just IDs if you don't have full objects
const url2 = utils.buildPortalPath({
collection: { shortId: 'abc123' },
productId: 'prod1'
})
// Returns: https://zt.smartlinks.io/c/abc123/prod1 (default domain)
Path Builder Function
buildPortalPath(params)
Builds a full portal URL based on the provided parameters. Returns full URL by default using collection.portalUrl or https://zt.smartlinks.io.
Parameters:
-
collection(required) - Collection object or{ shortId: string, portalUrl?: string }
Extracts:shortIdand optionalportalUrlfor base domain -
product(optional) - Full product object
Extracts:id,gtin, andownGtin(ownGtin is a critical product setting - read only, never overridden) -
productId(optional) - Just a product ID string
Use this if you don't have the full product object -
batch(optional) - Batch object
Extracts:idandexpiryDate -
batchId(optional) - Just a batch ID string
Use this if you don't have the full batch object (no expiry date) -
variant(optional) - Variant object OR just a variant ID string- If object: extracts
id - If string: uses as variant ID
- If object: extracts
-
proof(optional) - Proof object OR just a proof ID string- If object: extracts
id - If string: uses as proof ID
- If object: extracts
-
queryParams(optional) - Additional query parameters object -
pathOnly(optional, default:false) - Return only the path without domain
Set totrueto get/c/abc/prodinstead ofhttps://domain.com/c/abc/prod
Path Formats:
- Basic product:
/c/{shortId}/{productId} - With proof:
/c/{shortId}/{productId}/{proofId} - GTIN (own):
/01/{gtin}(when product.ownGtin is true) - GTIN (not own):
/gc/{shortId}/01/{gtin}(when product.ownGtin is false) - With batch: adds
/10/{batchId}and optionally?17={expiryDate} - With variant: adds
/22/{variantId}
Examples
Full URL (Default Behavior)
// Returns full URL using collection.portalUrl
utils.buildPortalPath({
collection: myCollection, // uses collection.portalUrl
product: myProduct
})
// Returns: https://portal.smartlinks.io/c/abc123/prod123
// Without portalUrl, uses default domain
utils.buildPortalPath({
collection: { shortId: 'abc123' },
productId: 'prod1'
})
// Returns: https://zt.smartlinks.io/c/abc123/prod1
// With proof object
utils.buildPortalPath({
collection: myCollection,
product: myProduct,
proof: myProof // extracts id
})
// Returns: https://portal.smartlinks.io/c/abc123/prod123/proof789
Path Only (No Domain)
// Set pathOnly: true to get just the path
utils.buildPortalPath({
collection: myCollection,
product: myProduct,
pathOnly: true
})
// Returns: /c/abc123/prod123
// Useful when you need to build your own full URL
const path = utils.buildPortalPath({
collection: { shortId: 'abc123' },
productId: 'prod1',
pathOnly: true
})
const customUrl = `https://mycustomdomain.com${path}`
// Result: https://mycustomdomain.com/c/abc123/prod1
GTIN Paths
// Product owns GTIN (ownGtin read from product.ownGtin)
utils.buildPortalPath({
collection: myCollection,
product: myProduct // if myProduct.ownGtin === true
})
// Returns: https://portal.smartlinks.io/01/1234567890123
// Product doesn't own GTIN (shared/master GTIN)
utils.buildPortalPath({
collection: myCollection,
product: myProduct // if myProduct.ownGtin === false
})
// Returns: https://portal.smartlinks.io/gc/abc123/01/1234567890123
With Batch Object or ID
// Batch object includes expiry date
utils.buildPortalPath({
collection: myCollection,
product: myProduct,
batch: myBatch // extracts id and expiryDate
})
// Returns: https://portal.smartlinks.io/01/1234567890123/10/batch456?17=260630
// Just batch ID (no expiry)
utils.buildPortalPath({
collection: myCollection,
product: myProduct,
batchId: 'batch456' // just string, no expiry date
})
// Returns: https://portal.smartlinks.io/01/1234567890123/10/batch456
With Variant
utils.buildPortalPath({
collection: myCollection,
product: myProduct,
batch: myBatch,
variant: myVariant // extracts id
})
// Returns: https://portal.smartlinks.io/01/1234567890123/10/batch456/22/var1?17=260630
// Or just variant ID
utils.buildPortalPath({
collection: myCollection,
product: myProduct,
variant: 'var1'
})
// Returns: https://portal.smartlinks.io/01/1234567890123/22/var1
With Query Parameters
utils.buildPortalPath({
collection: myCollection,
product: myProduct,
queryParams: {
utm_source: 'email',
utm_campaign: 'launch',
lang: 'fr'
}
})
// Returns: https://portal.smartlinks.io/c/abc123/prod123?utm_source=email&utm_campaign=launch&lang=fr
Use Cases
QR Code Generation
const qrUrl = utils.buildPortalPath({
collection: myCollection,
product: myProduct, // ownGtin read from product
batch: currentBatch, // includes expiry date
queryParams: { source: 'qr' }
})
// Use qrUrl to generate QR code
Email Campaign Links
const emailLink = utils.buildPortalPath({
collection: myCollection,
product: featuredProduct,
queryParams: {
utm_source: 'newsletter',
utm_medium: 'email',
utm_campaign: 'product-launch'
}
})
NFC Tag Programming
const nfcUrl = utils.buildPortalPath({
collection: myCollection,
product: myProduct,
queryParams: { nfc: '1' }
})
// Program NFC tag with nfcUrl
Dynamic Navigation
function getProductUrl(product: Product, collection: Collection) {
return utils.buildPortalPath({
collection,
product, // ownGtin automatically read from product
batch: product.currentBatch
})
}
TypeScript Support
The utility function is fully typed:
import type { PortalPathParams } from '@evrythng/smartlinks'
import type { Product, Collection } from '@evrythng/smartlinks'
const params: PortalPathParams = {
collection: myCollection,
product: myProduct
}
const path = utils.buildPortalPath(params)
Condition Validation Utility
The validateCondition function helps determine if content should be shown or hidden based on various criteria like geography, device type, user status, dates, and more.
Enable verbose tracing per invocation with debugConditions, or set globalThis.SMARTLINKS_CONDITION_DEBUG = true in a browser/devtools session to trace every evaluation.
Basic Usage
import { utils } from '@proveanything/smartlinks'
// Check if user is in EU
const canShow = await utils.validateCondition({
condition: {
type: 'and',
conditions: [{
type: 'country',
regions: ['eu'],
contains: true
}]
},
user: {
valid: true,
location: { country: 'DE' }
}
})
// Multiple conditions with AND logic
const showFeature = await utils.validateCondition({
condition: {
type: 'and',
conditions: [
{ type: 'user', userType: 'valid' },
{ type: 'device', displays: ['mobile'], contains: true },
{ type: 'date', dateTest: 'after', afterDate: '2026-01-01' }
]
},
user: { valid: true },
stats: { mobile: true }
})
Supported Condition Types
Country-Based Conditions
Filter by country codes or predefined regions (EU, EEA, UK, North America, Asia Pacific):
await utils.validateCondition({
condition: {
type: 'and',
conditions: [{
type: 'country',
regions: ['eu', 'uk'],
contains: true // true = show IN these regions, false = hide IN these regions
}]
},
user: { valid: true, location: { country: 'FR' } }
})
// Regions and explicit countries can be combined
await utils.validateCondition({
condition: {
type: 'and',
conditions: [{
type: 'country',
regions: ['eu'],
countries: ['CH'],
contains: true
}]
},
user: { valid: true, location: { country: 'CH' } }
})
// Or specific countries
await utils.validateCondition({
condition: {
type: 'and',
conditions: [{
type: 'country',
countries: ['US', 'CA', 'MX'],
contains: true
}]
},
user: { valid: true, location: { country: 'US' } }
})
Device & Platform Conditions
Target specific devices or platforms:
await utils.validateCondition({
condition: {
type: 'and',
conditions: [{
type: 'device',
displays: ['ios', 'android', 'mobile'],
contains: true
}]
},
stats: {
platform: { ios: true },
mobile: true
}
})
Supported displays: 'android', 'ios', 'win', 'mac', 'desktop', 'mobile'
User Status Conditions
Check authentication and permissions:
// Logged in users only
await utils.validateCondition({
condition: {
type: 'and',
conditions: [{ type: 'user', userType: 'valid' }]
},
user: { valid: true, uid: 'user123' }
})
// Collection admins only
await utils.validateCondition({
condition: {
type: 'and',
conditions: [{ type: 'user', userType: 'admin' }]
},
user: { valid: true, uid: 'user123' },
collection: { id: 'col1', roles: { 'user123': 'admin' } }
})
// Proof owners only
await utils.validateCondition({
condition: {
type: 'and',
conditions: [{ type: 'user', userType: 'owner' }]
},
user: { valid: true, uid: 'user123' },
proof: { userId: 'user123' }
})
User types: 'valid', 'invalid', 'owner', 'admin', 'group'
Date & Time Conditions
Show/hide content based on dates:
// Show after specific date
await utils.validateCondition({
condition: {
type: 'and',
conditions: [{
type: 'date',
dateTest: 'after',
afterDate: '2026-06-01'
}]
}
})
// Show during date range
await utils.validateCondition({
condition: {
type: 'and',
conditions: [{
type: 'date',
dateTest: 'between',
rangeDate: ['2026-01-01', '2026-12-31']
}]
}
})
Date tests: 'before', 'after', 'between'
Product & Tag Conditions
Filter by specific products or product tags:
// Specific products
await utils.validateCondition({
condition: {
type: 'and',
conditions: [{
type: 'product',
productIds: ['prod1', 'prod2'],
contains: true
}]
},
product: { id: 'prod1' }
})
// Products with specific tags
await utils.validateCondition({
condition: {
type: 'and',
conditions: [{
type: 'tag',
tags: ['premium', 'featured'],
contains: true
}]
},
product: { id: 'prod1', tags: { premium: true } }
})
Item Status Conditions
Check proof/item status:
await utils.validateCondition({
condition: {
type: 'and',
conditions: [{
type: 'itemStatus',
statusType: 'isClaimable'
}]
},
proof: { claimable: true }
})
Status types: 'isClaimable', 'notClaimable', 'noProof', 'hasProof', 'isVirtual', 'notVirtual'
Version Conditions
For A/B testing or versioned content:
await utils.validateCondition({
condition: {
type: 'and',
conditions: [{
type: 'version',
versions: ['v2', 'v3'],
contains: true
}]
},
stats: { version: 'v2' }
})
Value Comparison Conditions
Compare custom field values:
await utils.validateCondition({
condition: {
type: 'and',
conditions: [{
type: 'value',
field: 'product.inventory.quantity', // dot notation
fieldType: 'integer',
validationType: 'greater',
value: 10
}]
},
product: { inventory: { quantity: 25 } }
})
Validation types: 'equal', 'not', 'greater', 'less'
Field types: 'string', 'boolean', 'integer', 'number'
Geofence Conditions
Location-based restrictions using bounding boxes:
await utils.validateCondition({
condition: {
type: 'and',
conditions: [{
type: 'geofence',
top: 50.0,
bottom: 40.0,
left: -10.0,
right: 5.0,
contains: true // true = inside box, false = outside box
}]
},
user: {
valid: true,
location: { latitude: 45.0, longitude: 0.0 }
}
})
Nested Conditions
Reference other condition sets for reusability:
await utils.validateCondition({
condition: {
type: 'and',
conditions: [{
type: 'condition',
conditionId: 'mobile-users-condition',
passes: true // true = must pass, false = must fail
}]
},
conditionId: 'mobile-users-condition',
fetchCondition: async (collectionId, conditionId) => {
// Your logic to fetch condition by ID
return { type: 'and', conditions: [...] }
},
collection: { id: 'col1' }
})
Combining Conditions (AND/OR Logic)
// AND logic (all must pass)
await utils.validateCondition({
condition: {
type: 'and',
conditions: [
{ type: 'user', userType: 'valid' },
{ type: 'device', displays: ['mobile'], contains: true },
{ type: 'country', regions: ['eu'], contains: true }
]
},
user: { valid: true, location: { country: 'FR' } },
stats: { mobile: true }
})
// OR logic (any can pass)
await utils.validateCondition({
condition: {
type: 'or',
conditions: [
{ type: 'user', userType: 'admin' },
{ type: 'product', productIds: ['featured1'], contains: true }
]
},
user: { valid: false },
product: { id: 'featured1' }
})
Common Use Cases
Page Rendering Control
const showPremiumContent = await utils.validateCondition({
condition: {
type: 'and',
conditions: [
{ type: 'user', userType: 'valid' },
{ type: 'tag', tags: ['premium'], contains: true }
]
},
user: { valid: true },
product: { id: 'prod1', tags: { premium: true } }
})
if (showPremiumContent) {
// Render premium content
}
Regional Feature Rollout
const showNewFeature = await utils.validateCondition({
condition: {
type: 'and',
conditions: [
{ type: 'country', regions: ['northamerica'], contains: true },
{ type: 'date', dateTest: 'after', afterDate: '2026-03-01' }
]
},
user: { valid: true, location: { country: 'US' } }
})
### Debug Logging
Trace which condition is being evaluated, whether it passed, and why:
```typescript
await utils.validateCondition({
condition: {
type: 'and',
conditions: [
{ type: 'user', userType: 'valid' },
{ type: 'country', regions: ['eu'], contains: true }
]
},
user: { valid: true, location: { country: 'DE' } },
debugConditions: true
})
// Or enable globally in the browser console/devtools
globalThis.SMARTLINKS_CONDITION_DEBUG = true
If you want to route logs somewhere specific, pass a logger:
await utils.validateCondition({
condition: {
type: 'and',
conditions: [{ type: 'user', userType: 'valid' }]
},
user: { valid: true },
debugConditions: {
label: 'checkout-gate',
logger: (...args) => console.log(...args)
}
})
#### Mobile-Only Features
```typescript
const showMobileFeature = await utils.validateCondition({
condition: {
type: 'and',
conditions: [
{ type: 'device', displays: ['mobile'], contains: true }
]
},
stats: { mobile: true, platform: { ios: true } }
})
Available Regions
Predefined regions for country conditions:
- eu - European Union (27 member states)
- eea - European Economic Area (EU + EFTA countries)
- uk - United Kingdom
- northamerica - US, CA, MX
- asiapacific - AU, NZ, JP, KR, SG, HK, TW, TH, MY, PH, ID, VN, IN
More Examples
See examples/utils-demo.ts for comprehensive examples.
Related Documentation
- API Summary - Complete SDK reference with all namespaces and functions
- QR Codes - QR code lookup functions that work with generated paths
- NFC - NFC tag claiming and validation
- Collections - Collection management functions
- Products - Product CRUD operations
- Batches - Batch management
- Proofs - Proof creation and claiming