@taskon/widget-react
v0.1.0
Published
TaskOn React Widget Library
Readme
@taskon/widget-react
TaskOn React Widget - Embeddable white-label components for integrating TaskOn quest/task functionality into your application.
Installation
npm install @taskon/widget-react @taskon/core
# or
pnpm add @taskon/widget-react @taskon/core
# or
yarn add @taskon/widget-react @taskon/coreQuick Start
// Providers from core (minimal CSS ~3KB)
import { TaskOnProvider } from "@taskon/widget-react/core";
// Widgets from their sub-paths (isolated CSS)
import { QuestWidget } from "@taskon/widget-react/quest";
const App = () => (
<TaskOnProvider
config={{
clientId: "your-client-id",
}}
>
<YourApp />
</TaskOnProvider>
);Import Methods
Recommended: Sub-path Imports (Optimal CSS)
// Core: Providers and hooks only (~3KB CSS for Toast)
import { TaskOnProvider, ThemeProvider, useTaskOnAuth } from "@taskon/widget-react/core";
// Widgets: Each loads only its own CSS
import { QuestWidget } from "@taskon/widget-react/quest"; // ~26KB CSS
import { CommunityTaskList } from "@taskon/widget-react/community-task"; // ~51KB CSS
import { LeaderboardWidget } from "@taskon/widget-react/leaderboard"; // ~17KB CSS
import { UserCenterWidget } from "@taskon/widget-react/user-center"; // UserCenter CSS onlyAlternative: Main Entry Import (Loads All CSS)
// Loads ALL widget CSS (~92KB) - not recommended for production
import { TaskOnProvider, QuestWidget, CommunityTaskList } from "@taskon/widget-react";Usage Example
import { TaskOnProvider, useTaskOnAuth } from "@taskon/widget-react/core";
import { QuestWidget } from "@taskon/widget-react/quest";
const App = () => (
<TaskOnProvider
config={{
clientId: "your-client-id",
}}
>
<YourApp />
</TaskOnProvider>
);
// Your app controls the login UI
const YourApp = () => {
const { userId, login, logout } = useTaskOnAuth();
const { user, getSignature } = useYourAuth(); // Your auth hook
// When user logs in to your app, login to TaskOn
useEffect(() => {
if (user?.email && !userId) {
const { sign, timestamp } = getSignature(); // Get signature from your backend
login({ method: "email", value: user.email, sign, timestamp });
}
}, [user, userId]);
// When user logs out from your app, logout from TaskOn
useEffect(() => {
if (!user && userId) {
logout();
}
}, [user, userId]);
return (
<div>
{userId && <p>TaskOn User ID: {userId}</p>}
{/* Theme configured in TaskOn Dashboard */}
<QuestWidget widgetId={123} />
</div>
);
};Architecture
┌─ TaskOnProvider ─────────────────────────────────────────┐
│ config: { clientId } │
│ Purpose: Authentication only │
│ │
│ ┌─ Mode A: Cloud Config ──────────────────────────────┐ │
│ │ <QuestWidget widgetId={123} /> │ │
│ │ → Theme from TaskOn cloud │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─ Mode B: Local Theme ───────────────────────────────┐ │
│ │ <ThemeProvider theme={{ mode: 'dark' }}> │ │
│ │ <QuestWidget /> /* no widgetId */ │ │
│ │ </ThemeProvider> │ │
│ └─────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘Theme Source (mutually exclusive)
| Mode | Theme Source |
| --------------------- | ------------------------------------ |
| widgetId provided | Cloud config (ThemeProvider ignored) |
| No widgetId | ThemeProvider or default theme |
Security
TaskOn uses Client ID authentication to verify that widget requests come from authorized projects.
Step 1: Get Client ID from TaskOn Dashboard
Client ID: /KDiqEFNCaGTVTdTpCFrZOsUj5vDi5uGLSFmwyHeboE= (for X-API-Key header)Step 2: Configure TaskOnProvider
<TaskOnProvider
config={{
clientId: "your-client-id",
}}
>
<YourApp />
</TaskOnProvider>;HTTP Headers
All API requests include:
X-API-Key: your-client-id # Project authorization
Authorization: Bearer xxx # User authorization (after login)Security Best Practices
- Keep Client ID secure - Don't expose in public repositories
- Use HTTPS - All communication must be encrypted
TaskOnProvider
The root provider component for authentication. Must wrap your application.
Props
| Prop | Type | Required | Default | Description |
| ------------ | ------------------------ | -------- | ------- | -------------------- |
| config | TaskOnProviderConfig | Yes | - | Configuration object |
| children | ReactNode | Yes | - | Child components |
TaskOnProviderConfig
interface TaskOnProviderConfig {
// Required: Client ID for authentication (X-API-Key header)
clientId: string;
// Locale setting
locale?: "en" | "ko" | "ja" | "ru" | "es"; // default: auto-detect
// Wallet configuration (only needed if using wallet login)
walletConfig?: {
evmAdapter?: WalletAdapter; // Custom EVM wallet adapter
solanaAdapter?: WalletAdapter; // Custom Solana wallet adapter
};
// WalletConnect Project ID
// Only needed when you design Web3 wallet login or wallet-based rewards
// (wallet binding, on-chain verification, NFT/token claiming, etc.)
// Optional; SDK has a built-in default project ID
// For production, strongly recommended to use your own project ID
// Get your project ID at https://cloud.walletconnect.com
walletConnectProjectId?: string;
// Callback when user needs to login (e.g., clicks login overlay)
onRequestLogin?: () => void;
}Internationalization
Supported Locales
| Locale | Language |
| ------ | ----------------- |
| en | English (default) |
| ko | Korean |
| ja | Japanese |
| ru | Russian |
| es | Spanish |
Configuration
<TaskOnProvider
config={{
clientId: "your-client-id",
locale: "ko",
}}
>
<App />
</TaskOnProvider>Dynamic Locale Switching
Control locale via your own state:
const App = () => {
const [locale, setLocale] = useState("en");
return (
<TaskOnProvider config={{ clientId: "your-client-id", locale }}>
<select value={locale} onChange={(e) => setLocale(e.target.value)}>
<option value="en">English</option>
<option value="ko">한국어</option>
<option value="ja">日本語</option>
</select>
<QuestWidget widgetId={123} />
</TaskOnProvider>
);
};Locale Auto-Detection
When locale is not specified, TaskOn detects from browser language, falling back to en.
ThemeProvider
Optional provider for theme configuration. Supports nesting for different theme zones.
Props
| Prop | Type | Required | Default | Description |
| ------------ | --------------------- | -------- | -------- | -------------------- |
| theme | TaskOnThemeConfig | No | - | Theme configuration |
| children | ReactNode | Yes | - | Child components |
| inherit | boolean | No | true | Inherit parent theme |
TaskOnThemeConfig
interface TaskOnThemeConfig {
// Theme mode
mode?: "light" | "dark" | "auto"; // default: 'dark'
// Theme mode strategy (mainly for cloud dual mode)
modeStrategy?: "auto" | "toggle"; // default: 'auto'
// Compact mode
compact?: boolean; // default: false
// Seed tokens - algorithm input, auto-derives other values
seed?: SeedToken;
// Map tokens - override derived values
map?: MapToken;
// Optional: separate config for light/dark mode
light?: {
seed?: SeedToken;
map?: MapToken;
};
dark?: {
seed?: SeedToken;
map?: MapToken;
};
}
interface SeedToken {
colorPrimary?: string; // e.g., '#6366f1'
colorSecondary?: string;
colorSuccess?: string;
colorWarning?: string;
colorError?: string;
borderRadius?: number; // e.g., 8
fontSize?: number; // e.g., 14
fontFamily?: string;
}
interface MapToken {
// Primary colors (derived from seed.colorPrimary)
colorPrimary?: string;
colorPrimaryHover?: string;
colorPrimaryActive?: string;
colorPrimaryBg?: string;
// Background
colorBg?: string;
colorBgElevated?: string;
colorBgSpotlight?: string;
// Text
colorText?: string;
colorTextSecondary?: string;
colorTextTertiary?: string;
colorTextDisabled?: string;
colorLink?: string;
colorTextOnPrimary?: string;
// Border
colorBorder?: string;
colorBorderSecondary?: string;
// Layout
borderRadius?: number;
borderRadiusSm?: number;
borderRadiusLg?: number;
// Typography
fontSize?: number;
fontSizeSm?: number;
fontSizeLg?: number;
// Spacing
spacing?: number; // base spacing unit, e.g., 8
spacingXs?: number; // e.g., 4
spacingSm?: number; // e.g., 8
spacingMd?: number; // e.g., 16
spacingLg?: number; // e.g., 24
spacingXl?: number; // e.g., 32
}themeMode Override
SDK can control theme mode per widget using themeMode:
<QuestWidget widgetId={123} themeMode="light" />
<QuestWidget widgetId={123} themeMode="dark" />
<QuestWidget widgetId={123} themeMode="auto" />themeMode is supported by:
QuestWidgetCommunityTaskListLeaderboardWidgetUserCenterWidget
Priority rule:
themeMode(widget prop) has the highest priority when provided.- Recommended usage:
dual + togglein B-end for clearer mode ownership.
Token Priority
light/dark.map > light/dark.seed (derived) > map > seed (derived) > defaultTheme Inheritance
Nested ThemeProviders inherit from parent and can override specific values:
<TaskOnProvider config={{ clientId: "your-client-id" }}>
<ThemeProvider theme={{ mode: "light", seed: { colorPrimary: "#6366f1" } }}>
<Header /> {/* light + primary #6366f1 */}
<ThemeProvider theme={{ mode: "dark" }}>
<Sidebar /> {/* dark + inherits primary #6366f1 */}
</ThemeProvider>
<ThemeProvider theme={{ seed: { colorPrimary: "#ef4444" } }}>
<DangerZone /> {/* light + primary #ef4444 */}
</ThemeProvider>
</ThemeProvider>
</TaskOnProvider>Light/Dark Separate Config
Configure different themes for light and dark modes:
// Different primary colors for each mode
<ThemeProvider
theme={{
mode: 'auto',
light: { seed: { colorPrimary: '#6366f1' } },
dark: { seed: { colorPrimary: '#818cf8' } },
}}
>
<App />
</ThemeProvider>
// Override specific derived values
<ThemeProvider
theme={{
mode: 'auto',
light: {
seed: { colorPrimary: '#6366f1' },
map: { colorPrimaryHover: '#4f46e5' },
},
dark: {
seed: { colorPrimary: '#818cf8' },
map: { colorBg: '#0a0a0a' },
},
}}
>
<App />
</ThemeProvider>Disable Inheritance
Use inherit={false} for completely independent themes:
<ThemeProvider theme={{ mode: "dark" }}>
<DarkContent />
<ThemeProvider theme={{ mode: "light" }} inherit={false}>
<LightPopup /> {/* Fully independent light theme */}
</ThemeProvider>
</ThemeProvider>Widgets
Cloud Configuration
Widgets support cloud configuration via widgetId. Configure in TaskOn Dashboard and load at runtime:
// Cloud config includes: theme, feature flags, custom texts
<QuestWidget widgetId={123} />Widget Props
interface WidgetProps {
// Cloud widget ID from TaskOn Dashboard
widgetId?: number;
// Manual theme mode override (highest priority when provided)
// Recommended usage: pair with cloud dual+toggle for clearer ownership
themeMode?: "light" | "dark" | "auto";
// Custom class names for widget parts
classNames?: {
root?: string;
header?: string;
body?: string;
footer?: string;
// ... widget-specific parts
};
// Custom inline styles for widget parts
styles?: {
root?: React.CSSProperties;
header?: React.CSSProperties;
body?: React.CSSProperties;
footer?: React.CSSProperties;
// ... widget-specific parts
};
}Styling with classNames and styles
Widgets support fine-grained styling via classNames and styles props:
// Using classNames
<QuestWidget
widgetId={123}
classNames={{
root: 'my-quest-widget',
header: 'my-quest-header',
body: 'my-quest-body',
}}
/>
// Using inline styles
<QuestWidget
widgetId={123}
styles={{
root: { maxWidth: 400 },
header: { borderBottom: '1px solid #eee' },
body: { padding: 24 },
}}
/>
// Combining both
<QuestWidget
widgetId={123}
classNames={{ root: 'custom-widget' }}
styles={{ header: { backgroundColor: 'transparent' } }}
/>Each widget documents its available parts in its own API reference.
Usage Examples
// Example 1: Using cloud config (theme from Dashboard)
<TaskOnProvider config={{ clientId: 'your-client-id' }}>
<QuestWidget widgetId={123} />
<TaskWidget widgetId={456} />
</TaskOnProvider>
// Example 2: Using local theme (no cloud config)
<TaskOnProvider config={{ clientId: 'your-client-id' }}>
<ThemeProvider theme={{ mode: 'dark', seed: { colorPrimary: '#6366f1' } }}>
<QuestWidget />
<TaskWidget />
</ThemeProvider>
</TaskOnProvider>
// Example 3: Different local themes for different areas
<TaskOnProvider config={{ clientId: 'your-client-id' }}>
<ThemeProvider theme={{ mode: 'light' }}>
<TaskWidget />
</ThemeProvider>
<ThemeProvider theme={{ mode: 'dark', compact: true }}>
<QuestWidget />
</ThemeProvider>
</TaskOnProvider>
// Example 4: Mixed - some with cloud config, some with local theme
<TaskOnProvider config={{ clientId: 'your-client-id' }}>
{/* Cloud config */}
<QuestWidget widgetId={123} />
{/* Local theme */}
<ThemeProvider theme={{ mode: 'dark' }}>
<TaskWidget />
</ThemeProvider>
</TaskOnProvider>Login Methods
TaskOn uses a unified login method with signature verification. All login methods require a backend signature for security.
Unified Login API
import { useTaskOnAuth } from "@taskon/widget-react";
const { login } = useTaskOnAuth();
// Login with any method
await login({
method: "evm_wallet", // Login method type
value: "0x1234...", // Address / email / OAuth token
sign: signatureFromBackend, // Backend signature
timestamp: 1700000000000, // Signature timestamp (milliseconds)
});Supported Methods
| Method | method value | value parameter |
| ------------- | ----------------- | ----------------------- |
| EVM Wallet | evm_wallet | Wallet address (0x...) |
| Solana Wallet | solana_wallet | Wallet address (base58) |
| Email | email | Email address |
| Discord | discord | OAuth token |
| Twitter | twitter | OAuth token |
| Telegram | telegram | OAuth token |
LoginParams Type
interface LoginParams {
method: LoginMethod; // Login method type
value: string; // Address / email / OAuth token
sign: string; // Backend signature
timestamp: number; // Signature timestamp (milliseconds)
}
type LoginMethod =
| "evm_wallet"
| "solana_wallet"
| "email"
| "discord"
| "twitter"
| "telegram";Wallet Integration
When tasks or rewards involve blockchain operations (e.g., token rewards, NFT minting, on-chain verification), widgets need to interact with the user's wallet for:
- Connecting wallet - Get user's wallet address
- Signing messages - Verify wallet ownership
- Calling contracts - Claim on-chain rewards, execute transactions
Overview
TaskOn widgets include built-in wallet management, but also support external wallet providers for seamless integration with existing dApps. When wrapped in an external provider, the widget automatically detects and reuses your wallet management.
Wallet Management
TaskOn provides flexible wallet integration options:
| Setup | Behavior |
| -------------- | ------------------------------------- |
| Custom adapter | Uses your provided WalletAdapter |
| Default | Uses built-in wallet picker adapter |
Custom Wallet Adapter (Recommended)
If you want full control over wallet connection (e.g., using RainbowKit, Web3Modal), provide a custom adapter:
import { useMemo } from "react";
import { createWalletAdapter } from "./my-wallet-adapter";
const App = () => {
const evmAdapter = useMemo(() => createWalletAdapter(), []);
return (
<TaskOnProvider
config={{
clientId: "your-client-id",
walletConfig: {
evmAdapter,
},
}}
>
<MainContent />
</TaskOnProvider>
);
};Note: keep evmAdapter reference stable (for example via useMemo) to avoid
re-creating adapters and resetting wallet state on every render.
Built-in Wallet Support
If no custom adapter is provided, TaskOn automatically uses built-in wallet picker flow:
// No wallet config needed
<TaskOnProvider config={{ clientId: "your-client-id" }}>
<App />
</TaskOnProvider>Built-in Wallet Binding Dialog
When tasks require wallet binding (e.g., on-chain verification), TaskOn shows a built-in wallet selection dialog:
Desktop (without adapter):
- MetaMask
- Bitget Wallet
- OKX Wallet
- WalletConnect (uses SDK default project ID if not configured; not recommended for production)
Mobile (non-Dapp browser):
- WalletConnect only (uses SDK default project ID if not configured; not recommended for production)
Mobile (Dapp browser / wallet app):
- Uses injected provider directly
Only configure walletConnectProjectId when your product needs Web3 wallet login
or wallet-based rewards (wallet binding, on-chain verification, NFT/token claiming).
To enable WalletConnect in the dialog:
<TaskOnProvider
config={{
clientId: "your-client-id",
walletConnectProjectId: "your-project-id", // Get from cloud.walletconnect.com
}}
>
<App />
</TaskOnProvider>Built-in Wallet Management
If no external adapter is provided, the widget uses built-in wallet management. No configuration needed:
<TaskOnProvider config={{ clientId: "your-client-id" }}>
<App /> {/* Widget handles wallet connection internally */}
</TaskOnProvider>Configuration Options
interface WalletConfig {
// EVM wallet adapter (highest priority)
evmAdapter?: WalletAdapter;
// Solana wallet adapter (highest priority)
solanaAdapter?: WalletAdapter;
}Custom Wallet Adapter
For projects with their own wallet management:
// Example: Custom wallet management
const useCustomWalletAdapter = (): WalletAdapter => {
const { openWalletModal, connectedAddress, chainId } = useYourWalletManager();
return {
connect: async () => {
// Open your wallet selection modal, return selected address
const address = await openWalletModal();
return address;
},
disconnect: async () => {
await yourDisconnectLogic();
},
signMessage: async (message) => {
return await yourSignMessageLogic(message);
},
getAddress: () => connectedAddress,
getChainId: () => chainId,
switchNetwork: async (chainId) => {
await yourSwitchNetworkLogic(chainId);
},
};
};
const App = () => {
const evmAdapter = useCustomWalletAdapter();
return (
<TaskOnProvider
config={{
clientId: "your-client-id",
walletConfig: { evmAdapter },
}}
>
<YourApp />
</TaskOnProvider>
);
};Priority Order
When multiple options are available:
- Custom Adapter -
walletConfig.evmAdapter/solanaAdapter(highest) - Built-in Adapter - SDK wallet picker adapter for EVM wallets (fallback)
Hooks
useTaskOnAuth
Access TaskOn authentication with unified login method.
import { useTaskOnAuth } from "@taskon/widget-react";
const Component = () => {
const {
// State
userId, // TaskOn user ID (number | null)
isLoggedIn, // Whether user is logged in
isInitializing, // Whether provider is initializing
// Unified login method
login, // (params: LoginParams) => Promise<void>
// Logout
logout, // () => void
} = useTaskOnAuth();
return <div>TaskOn ID: {userId}</div>;
};Login Function
// Unified login method
login: (params: LoginParams) => Promise<void>;
// LoginParams
interface LoginParams {
method: LoginMethod; // Login method type
value: string; // Address / email / OAuth token
sign: string; // Backend signature
timestamp: number; // Signature timestamp (milliseconds)
}
// Logout
logout: () => void;useTaskOnTheme
Access current theme. Must be used within ThemeProvider.
import { useTaskOnTheme } from "@taskon/widget-react";
const Component = () => {
const theme = useTaskOnTheme();
return (
<div
style={{
background: theme.tokens.colorBg,
color: theme.tokens.colorText,
padding: theme.tokens.spacingMd,
borderRadius: theme.tokens.borderRadius,
}}
>
Current mode: {theme.mode}
</div>
);
};Integration Examples
// Example 1: With EVM Wallet
const EVMWalletIntegration = () => {
const { evmAddress } = useWallet(); // TaskOn wallet hook
const { userId, login } = useTaskOnAuth();
const handleLogin = async () => {
if (evmAddress && !userId) {
// Get signature from your backend
const { sign, timestamp } = await fetchSignatureFromBackend(evmAddress);
await login({
method: "evm_wallet",
value: evmAddress,
sign,
timestamp,
});
}
};
useEffect(() => {
handleLogin();
}, [evmAddress, userId]);
return <div>{userId ? `TaskOn: ${userId}` : "Not logged in"}</div>;
};
// Example 2: With Custom Wallet Adapter
const CustomWalletIntegration = () => {
const { evmAddress, connectEvm } = useWallet();
const { userId, login } = useTaskOnAuth();
const handleLogin = async () => {
if (publicKey && !userId) {
const address = publicKey.toBase58();
const { sign, timestamp } = await fetchSignatureFromBackend(address);
await login({
method: "solana_wallet",
value: address,
sign,
timestamp,
});
}
};
useEffect(() => {
handleLogin();
}, [publicKey, userId]);
return <div>{userId ? `TaskOn: ${userId}` : "Not logged in"}</div>;
};
// Example 3: Email login
const EmailLogin = () => {
const { login } = useTaskOnAuth();
const handleEmailLogin = async (email: string) => {
const { sign, timestamp } = await fetchSignatureFromBackend(email);
await login({
method: "email",
value: email,
sign,
timestamp,
});
};
return (
<button onClick={() => handleEmailLogin("[email protected]")}>Login</button>
);
};
// Example 4: Discord OAuth callback
const DiscordCallback = () => {
const { login } = useTaskOnAuth();
useEffect(() => {
// After your Discord OAuth flow
const processOAuth = async () => {
const oauthToken = getDiscordTokenFromOAuth();
const { sign, timestamp } = await fetchSignatureFromBackend(oauthToken);
await login({
method: "discord",
value: oauthToken,
sign,
timestamp,
});
};
processOAuth();
}, []);
return <div>Processing...</div>;
};WalletAdapter Interface
For custom wallet integration:
interface WalletAdapter {
// Required
connect: () => Promise<string>;
disconnect: () => Promise<void>;
signMessage: (message: string) => Promise<string>;
getAddress: () => string | null;
// Optional (EVM only)
getChainId?: () => number | null;
switchNetwork?: (chainId: number) => Promise<void>;
// Optional (Event subscriptions)
onAccountChange?: (callback: (address: string | null) => void) => () => void;
onChainChange?: (callback: (chainId: number) => void) => () => void;
}Types
TaskOnAuthState
interface TaskOnAuthState {
userId: number | null; // TaskOn user ID (null if not logged in)
isLoggedIn: boolean; // Whether user is logged in
isInitializing: boolean; // Whether provider is initializing
}LoginParams
interface LoginParams {
method: LoginMethod; // Login method type
value: string; // Address / email / OAuth token
sign: string; // Backend signature
timestamp: number; // Signature timestamp (milliseconds)
}
type LoginMethod =
| "evm_wallet"
| "solana_wallet"
| "email"
| "discord"
| "twitter"
| "telegram";TaskOnTheme
The resolved theme object returned by useTaskOnTheme():
interface TaskOnTheme {
mode: "light" | "dark";
compact: boolean;
// All tokens are resolved (seed + derived + overrides)
tokens: {
// Primary colors
colorPrimary: string;
colorPrimaryHover: string;
colorPrimaryActive: string;
colorPrimaryBg: string;
// Secondary colors
colorSecondary: string;
// Status colors
colorSuccess: string;
colorWarning: string;
colorError: string;
// Background
colorBg: string;
colorBgElevated: string;
colorBgSpotlight: string;
// Text
colorText: string;
colorTextSecondary: string;
colorTextTertiary: string;
colorTextDisabled: string;
// Border
colorBorder: string;
colorBorderSecondary: string;
// Layout
borderRadius: number;
borderRadiusSm: number;
borderRadiusLg: number;
// Typography
fontSize: number;
fontSizeSm: number;
fontSizeLg: number;
fontFamily: string;
// Spacing
spacing: number;
spacingXs: number;
spacingSm: number;
spacingMd: number;
spacingLg: number;
spacingXl: number;
};
}SSR Compatibility
This package is SSR-compatible:
- All components are marked with
'use client' - Browser APIs are safely wrapped
- No hydration mismatches
Works with:
- Next.js App Router
- Next.js Pages Router
- Remix
- Other React SSR frameworks
Peer Dependencies
react>= 18.0.0react-dom>= 18.0.0@taskon/core>= 0.0.0
Optional Peer Dependencies
Install these only when you need Web3 wallet login or wallet-based reward flows. For WalletConnect support in the built-in wallet binding dialog:
npm install @walletconnect/ethereum-provider @walletconnect/modalThen configure your project ID:
<TaskOnProvider
config={{
clientId: "your-client-id",
walletConnectProjectId: "your-walletconnect-project-id",
}}
>
<App />
</TaskOnProvider>Get your WalletConnect Project ID at https://cloud.walletconnect.com
If not configured, the SDK will use a built-in default WalletConnect project ID.
For production use, strongly recommend configuring your own walletConnectProjectId.
Limitations
- Quest Widget does not support opening pre-task targets from
CommunityPreTaskeligibility.- In eligibility rows, pre-task names are displayed as plain text (non-clickable).
- Community names are hidden for
CommunityPreTask,CommunityUserPoints, andCommunityUserLevelrows. DiscordRolekeeps originalin {community}display and usesserver_urlas link when available.
- CommunityTask eligibility
CommunityPreTasksupports clicking task names to switch task dialogs.
License
MIT
