Triggers Integration Guide
Overview
Trigger Kit is a powerful library for integrating blockchain widgets into your React applications. It provides a seamless way to import and execute blockchain actions through URLs or metadata objects, with full support for wagmi and various wallet connections.
You can integrate widgets in multiple ways, from simple URL-based integration to advanced API-based customization. This guide walks you through each method, increasing in complexity.
Installation
Install the required packages:
npm install @sherrylinks/slinks @sherrylinks/slinks-core
Peer Dependencies
Make sure you have these peer dependencies installed:
npm install wagmi viem @tanstack/react-query framer-motion react react-dom
Quick Start
1. Import Required Styles
Add the Relayer CSS to your application:
import '@sherrylinks/slinks/index.css';
2. Create a Wagmi Adapter
import { createWagmiAdapter } from '@sherrylinks/slinks';
import { useConfig } from 'wagmi';
function MyApp() {
const config = useConfig(); // Your wagmi config
const adapter = createWagmiAdapter(config);
return <div>{/* Your app content */}</div>;
}
import { Trigger } from '@sherrylinks/slinks';
function MyTriggerComponent() {
return <Trigger url="https://api.relayer.fi/v1/widget/example/metadata" adapter={adapter} enableAnalytics={true} />;
}
URL Requirements: Ensure that the provided URL returns valid metadata. The Trigger component will fetch the metadata from the URL and validate it. If the metadata is valid, a widget will be rendered. Invalid metadata will result in an error state.
Integration Methods
This section covers different ways to integrate widgets, from the simplest to the most advanced.
Method 1: Simple URL Integration
The simplest way to integrate a widget is by providing a URL that returns valid metadata.
Use case: When you have a direct URL to widget metadata.
import { Trigger } from '@sherrylinks/slinks';
function URLTrigger({ adapter }) {
return (
<Trigger
url="https://api.relayer.fi/v1/widget/example/metadata"
adapter={adapter}
enableAnalytics={true}
/>
);
}
Pros:
- Simplest integration method
- No additional setup required
- Widget is automatically validated
Cons:
- Limited customization options
- Requires a valid metadata endpoint
Method 2: Directory API Integration
Fetch available widgets from the Relayer directory and display them dynamically.
Use case: When you want to show a curated list of available widgets to users.
import { Trigger } from '@sherrylinks/slinks';
import { useState, useEffect } from 'react';
function DirectoryTriggers({ adapter }) {
const [widgets, setWidgets] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchWidgets = async () => {
try {
const response = await fetch('https://api.relayer.fi/v1/directory/v1');
const data = await response.json();
setWidgets(data.widgets);
} catch (error) {
console.error('Error fetching widgets:', error);
} finally {
setLoading(false);
}
};
fetchWidgets();
}, []);
if (loading) return <div>Loading widgets...</div>;
return (
<div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))',
gap: '20px',
}}
>
{widgets
.filter(widget => widget.state === 'trusted') // Only show trusted widgets
.map(widget => (
<Trigger
key={widget.id}
url={`${widget.host}${widget.path}`}
adapter={adapter}
enableAnalytics={true}
/>
))}
</div>
);
}
Directory API Response Structure
The directory API returns a structured response with available widgets:
{
"lastUpdated": "2025-07-11T17:39:19.431Z",
"version": "1.0.0",
"widgets": [
{
"id": "e2349bf1-0893-44cd-a5aa-0f8104b7094d",
"host": "https://api.relayer.fi",
"state": "trusted",
"category": "Relayer KOL",
"subcategory": "Swap",
"verifiedAt": "2025-07-11T15:51:49.610392",
"protocol": "Protocol",
"path": "/v1/widget/e2349bf1-0893-44cd-a5aa-0f8104b7094d/metadata",
"source": "chat"
}
],
"templates": [...],
"maliciousDomains": [...]
}
Pros:
- Access to curated widget list
- Can filter by category, protocol, or state
- Automatic updates when new widgets are added
Cons:
- Requires network request
- Limited to widgets in the directory
Define widgets using metadata objects directly in your code.
Use case: When you want full control over widget configuration and don’t need to fetch from an API.
Basic Setup
First, install the Relayer SDK for metadata validation:
npm install @sherrylinks/sherry-sdk
import { Trigger } from '@sherrylinks/slinks';
import { createMetadata } from '@sherrylinks/sherry-sdk';
import type { ValidatedMetadata } from '@sherrylinks/sherry-sdk';
function CustomWidget({ adapter }) {
const customMetadata = {
url: 'https://example.com',
icon: 'https://example.com/icon.png',
title: 'My Custom Widget',
description: 'A custom blockchain widget',
baseUrl: 'https://api.example.com',
actions: [
{
type: 'transfer',
label: 'Send 0.01 ETH',
to: '0x742d35Cc6634C0532925a3b8D000b7AA5b7eA48C',
amount: 0.01,
chains: {
source: 1, // Ethereum mainnet
},
},
],
};
// Validate and create metadata
const validatedMetadata: ValidatedMetadata = createMetadata(customMetadata);
return (
<Trigger
metadata={validatedMetadata}
adapter={adapter}
securityState="unknown" // Custom metadata widgets appear as unverified
enableAnalytics={true}
/>
);
}
Pros:
- Full control over widget configuration
- No network requests needed
- Can be statically defined
Cons:
- Widgets appear as unverified
- Requires manual metadata creation
- Need to understand metadata structure
Security State: Widgets created with custom metadata will always appear as unverified to users, as they haven’t gone through the official verification process. Always validate your metadata using createMetadata before rendering.
Method 4: API-Based Customization (Advanced)
With your API key, you can fetch metadata from Relayer’s widget endpoints, customize it, and render personalized widgets.
Use case: When you need to personalize widgets based on user preferences, modify parameters dynamically, or create white-label experiences.
Basic API Customization
import { Trigger, createMetadata } from '@sherrylinks/slinks';
import { useState, useEffect } from 'react';
function CustomizedWidget({ adapter, apiKey, widgetId }) {
const [metadata, setMetadata] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchAndCustomizeMetadata = async () => {
try {
// Fetch metadata from Relayer API using your API key
const response = await fetch(
`https://api.relayer.fi/v1/widget/${widgetId}/metadata`,
{
headers: {
'Authorization': `ApiKey ${apiKey}`,
'Content-Type': 'application/json',
},
}
);
if (!response.ok) {
throw new Error('Failed to fetch metadata');
}
const fetchedMetadata = await response.json();
// Customize the metadata
const customizedMetadata = {
...fetchedMetadata,
title: 'My Customized Widget', // Override title
description: 'This widget has been customized for my use case',
actions: fetchedMetadata.actions.map(action => ({
...action,
label: `Custom ${action.label}`,
// Modify amounts, addresses, or other parameters as needed
})),
};
// Validate the customized metadata
const validatedMetadata = createMetadata(customizedMetadata);
setMetadata(validatedMetadata);
} catch (error) {
console.error('Error fetching or customizing metadata:', error);
} finally {
setLoading(false);
}
};
fetchAndCustomizeMetadata();
}, [apiKey, widgetId]);
if (loading) return <div>Loading widget...</div>;
if (!metadata) return <div>Failed to load widget</div>;
return (
<Trigger
metadata={metadata}
adapter={adapter}
securityState="verified" // Metadata from API is verified
enableAnalytics={true}
/>
);
}
Advanced Customization Example
Apply complex customizations based on user preferences or business logic:
import { Trigger, createMetadata } from '@sherrylinks/slinks';
import { useState, useEffect } from 'react';
function AdvancedCustomizedWidget({ adapter, apiKey, widgetId, userPreferences }) {
const [metadata, setMetadata] = useState(null);
useEffect(() => {
const customizeWidget = async () => {
try {
// Fetch original metadata
const response = await fetch(
`https://api.relayer.fi/v1/widget/${widgetId}/metadata`,
{
headers: {
'Authorization': `ApiKey ${apiKey}`,
},
}
);
const originalMetadata = await response.json();
// Apply customizations based on user preferences
const customizedMetadata = {
...originalMetadata,
actions: originalMetadata.actions.map(action => {
// Example: Adjust amounts based on user tier
if (action.type === 'transfer' && userPreferences.tier === 'premium') {
return {
...action,
amount: action.amount * 1.5, // Premium users get 50% more
};
}
// Example: Change default recipient for transfers
if (action.type === 'transfer' && userPreferences.defaultRecipient) {
return {
...action,
to: userPreferences.defaultRecipient,
};
}
return action;
}),
};
const validatedMetadata = createMetadata(customizedMetadata);
setMetadata(validatedMetadata);
} catch (error) {
console.error('Error customizing widget:', error);
}
};
customizeWidget();
}, [apiKey, widgetId, userPreferences]);
if (!metadata) return null;
return (
<Trigger
metadata={metadata}
adapter={adapter}
securityState="verified"
enableAnalytics={true}
/>
);
}
API Key Required: To fetch metadata from Relayer’s widget endpoints, you need a valid API key. Include it in the Authorization header using the format ApiKey {your_api_key}. The fetched metadata can be customized before validation and rendering, allowing you to create personalized widget experiences for your users.
Pros:
- Access to verified widgets from Relayer API
- Full customization capabilities
- Can personalize based on user data
- Widgets maintain verified status
Cons:
- Requires API key
- More complex implementation
- Additional network requests
Advanced Configuration
Security States
Control how security warnings are displayed to users:
<Trigger
metadata={validatedMetadata}
adapter={adapter}
securityState="verified" // Options: "unknown", "malicious", "verified"
/>
Security States:
"verified": Widget has been verified by Relayer (from API endpoints)
"unknown": Widget source is not verified (custom metadata)
"malicious": Widget has been flagged as potentially unsafe
Analytics
Analytics are automatically collected for all integrations. The enableAnalytics option will be deprecated in future versions as analytics collection will always be active.
<Trigger
url="https://example.com/api/widget"
adapter={adapter}
enableAnalytics={true} // Always collected - this option will be deprecated
/>
Complete Examples
Display multiple widgets in a grid layout:
import React from 'react';
import { Trigger, createWagmiAdapter } from '@sherrylinks/slinks';
import { useConfig } from 'wagmi';
import '@sherrylinks/slinks/index.css';
function WidgetContainer() {
const config = useConfig();
const adapter = createWagmiAdapter(config);
const widgets = [
'https://api.relayer.fi/v1/widget/example-1/metadata',
'https://api.relayer.fi/v1/widget/example-2/metadata',
];
return (
<div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))',
gap: '20px',
padding: '20px',
}}
>
{widgets.map((url, index) => (
<Trigger
key={index}
url={url}
adapter={adapter}
enableAnalytics={true}
/>
))}
</div>
);
}
export default WidgetContainer;
Fetch and filter widgets from the directory:
// Fetch all trusted widgets
const response = await fetch('https://api.relayer.fi/v1/directory/v1');
const directory = await response.json();
// Filter by category
const swapWidgets = directory.widgets.filter(
widget => widget.state === 'trusted' && widget.subcategory === 'Swap',
);
// Filter by protocol
const protocolWidgets = directory.widgets.filter(
widget => widget.protocol === 'Protocol'
);
Best Practices
- Always validate metadata before passing to Trigger using
createMetadata
- Use proper error boundaries around Trigger components
- Test with different networks and wallet states
- Implement proper loading states for better UX
- Cache metadata when possible to improve performance
- Handle errors gracefully - provide fallback UI for failed widgets
- Use API keys securely - never expose them in client-side code if possible
Error Handling
The Trigger component handles errors gracefully:
- Invalid URLs show error states
- Malicious widgets are blocked automatically
- Network errors are displayed to users
- Failed transactions can be retried
- Validation errors prevent rendering invalid widgets
Always wrap Trigger components in error boundaries:
import { ErrorBoundary } from 'react-error-boundary';
function WidgetWithErrorBoundary({ adapter, url }) {
return (
<ErrorBoundary fallback={<div>Widget failed to load</div>}>
<Trigger url={url} adapter={adapter} />
</ErrorBoundary>
);
}
API Reference
Trigger Props
export type TriggerProps = {
adapter: RelayerAdapter;
enableAnalytics?: boolean; // 📊 Always collected - will be deprecated
player?: boolean;
} & (
| {
url: string;
metadata?: never;
securityState?: never;
}
| {
metadata: ValidatedMetadata;
securityState: TriggerSecurityState;
url?: string;
}
);
RelayerAdapter Interface
The adapter interface provides wallet connectivity:
interface RelayerAdapter {
connect(): Promise<string>;
sendTransaction(params: TransactionParams): Promise<{ hash: string }>;
signMessage(message: string): Promise<string>;
switchChain(chainId: number): Promise<void>;
getAddress(): Promise<string>;
getChainId(): Promise<number>;
isConnected(): Promise<boolean>;
}
Troubleshooting
Common Issues
- Wallet not connected: Ensure your wagmi config is properly set up
- Metadata validation errors: Check your metadata format using the Metadata Validation guide
- Network issues: Verify your RPC endpoints are correctly configured
- Style conflicts: Import the CSS file correctly:
import '@sherrylinks/slinks/index.css'
- API key errors: Verify your API key is valid and included in the Authorization header
Getting Help