Skip to content

TaskOnEmbed Class

TaskOnEmbed is the core class of the SDK used to embed TaskOn into third-party sites and communicate with the iframe via a message bridge.

Constructor

typescript
new TaskOnEmbed(config: TaskOnEmbedConfig)

Parameters

  • config: TaskOnEmbedConfig - configuration object

Example

typescript
import { TaskOnEmbed } from "@taskon/embed";

const embed = new TaskOnEmbed({
  baseUrl: "https://taskon.xyz", // or your white-label domain
  containerElement: "#taskon-container",
  width: "100%",
  height: "100%",
});

// Initialize the iframe
await embed.init();

Properties

initialized

Read-only property indicating whether the embed has been initialized.

typescript
get initialized(): boolean

Example

typescript
if (embed.initialized) {
  console.log("Embed is ready to use");
}

currentRoute

Get current iframe route.

typescript
get currentRoute(): string

Example

typescript
console.log("Current route:", embed.currentRoute);

Methods

init()

Initialize the embed iframe and establish communication.

typescript
init(): Promise<void>

Example

typescript
await embed.init();

login()

Request login inside the iframe. Supports both Email and EVM wallet authentication. Can be called when already logged in to switch accounts. Duplicate login with same account will be ignored.

typescript
login(request: LoginParams): Promise<void>

Parameters

  • request: LoginParams

Email login example

typescript
// Check if authorization is needed first
const isAuthorized = await embed.isAuthorized("Email", "user@example.com");

if (!isAuthorized) {
  // First time login - signature required
  await embed.login({
    type: "Email",
    account: "user@example.com",
    signature: serverSignature, // generated by your backend
    timestamp: Date.now(),
  });
} else {
  // Already authorized - no signature needed
  await embed.login({
    type: "Email",
    account: "user@example.com",
  });
}

EVM wallet login example

typescript
const isAuthorized = await embed.isAuthorized("WalletAddress", "0x1234...");

if (!isAuthorized) {
  await embed.login({
    type: "WalletAddress",
    account: "0x1234...",
    signature: serverSignature,
    timestamp: Date.now(),
    provider: window.ethereum, // Required for wallet operations
  });
} else {
  await embed.login({
    type: "WalletAddress",
    account: "0x1234...",
    provider: window.ethereum,
  });
}

Cross-account login example

typescript
// Switch directly from userA to userB without logout
await embed.login({
  type: "Email",
  account: "userB@example.com",
  signature: userBSignature, // Required if userB not authorized yet
  timestamp: userBTimestamp,
});

logout()

Request logout from current session with optional authorization cache control.

typescript
logout(options?: LogoutOptions): Promise<void>

Parameters

  • options?: LogoutOptions - Optional logout configuration
    • clearAuth?: boolean - Whether to clear authorization cache (default: false)
      • false: Keep auth cache for quick re-login (recommended for account switching)
      • true: Complete logout, clear all authorization cache (use for security-sensitive logout)

Examples

typescript
// Standard logout - keeps auth cache (recommended)
await embed.logout();;

// Complete logout - clears all authorization (use sparingly)
await embed.logout({ clearAuth: true });

### isAuthorized()

Check if the specified account has valid authorization cache. If true, login() can be called without signature/timestamp.

```typescript
isAuthorized(authType: AuthType, account: string): Promise<boolean>

Parameters

  • authType: AuthType - Authentication type ("Email" or "WalletAddress")
  • account: string - Account identifier (email address or wallet address)

Returns

  • Promise<boolean> - true if account has valid authorization cache, false if signature is required

Example

typescript
const isAuthorized = await embed.isAuthorized("Email", "user@example.com");
if (isAuthorized) {
  // No signature needed
  await embed.login({
    type: "Email",
    account: "user@example.com",
  });
} else {
  // Signature required
  const { signature, timestamp } = await getServerSignature("user@example.com");
  await embed.login({
    type: "Email",
    account: "user@example.com",
    signature,
    timestamp,
  });
}

updateSize()

Update iframe size.

typescript
updateSize(width?: string | number, height?: string | number): void

Example

typescript
embed.updateSize("100%", 720);

destroy()

Destroy the instance and release resources.

typescript
destroy(): void

Example

typescript
embed.destroy();

setRoute()

Set iframe internal route.

typescript
setRoute(fullPath: string): Promise<void>

Example

typescript
await embed.setRoute("/profile");

setLanguage()

Set the language for the iframe interface. The iframe will switch to the specified language immediately.

typescript
setLanguage(language: string): Promise<void>

Parameters

  • language: string - Language key (e.g., 'en', 'ko', 'ru', 'es', 'ja'). Fallback to 'en' if not supported.

Examples

typescript
// Switch to Korean
await embed.setLanguage("ko");

// Switch to Japanese
await embed.setLanguage("ja");

// Switch to Spanish
await embed.setLanguage("es");

// Unsupported language will fallback to English
await embed.setLanguage("fr"); // Falls back to 'en'

Supported Languages:

  • en - English
  • ko - Korean (한국어)
  • ja - Japanese (日本語)
  • ru - Russian (Русский)
  • es - Spanish (Español)

Events

Register events via embed.on(event, handler).

Available Events

  • loginRequired: () => void - Fired when iframe requires user authentication
  • routeChanged: (fullPath: string) => void - Fired when iframe internal route changes
  • taskCompleted: (data: TaskCompletedData) => void - Fired when user completes a task
  • bindConflict: (data: BindConflictData) => void - Fired when binding SNS or address fails because the account is already bound to another email

Event Examples

typescript
// Triggered when iframe needs user authentication
embed.on("loginRequired", () => {
  console.log("User authentication required");
  // Implement your authentication flow:
  // 1. Show login modal/form
  // 2. Get user credentials
  // 3. Generate signature on server
  // 4. Call embed.login() with signature
});

// Triggered when iframe internal route changes
embed.on("routeChanged", fullPath => {
  console.log("Internal route changed to:", fullPath);
  // Optional: Sync with external URL routing
  // window.history.replaceState(null, '', `/embed${fullPath}`);
});

// Triggered when user completes a task
embed.on("taskCompleted", data => {
  console.log("Task completed:", data);

  // Task completion data includes:
  console.log("Task ID:", data.taskId);
  console.log("Task Name:", data.taskName);
  console.log("Template ID:", data.templateId);
  console.log("Rewards:", data.rewards);

  // Handle task completion (analytics, notifications, etc.)
  analytics.track("task_completed", {
    task_id: data.taskId,
    task_name: data.taskName,
    rewards: data.rewards,
  });
});

// Triggered when binding SNS or address fails due to account conflict
// (White-label mode only)
embed.on("bindConflict", data => {
  console.log("Bind conflict detected:", data);

  // Bind conflict data includes:
  console.log("Already bound to email:", data.email);
  console.log("Bind type:", data.bindType); // "sns" or "address"

  if (data.bindType === "sns") {
    console.log("SNS type:", data.snsType); // e.g., "twitter", "discord"
    // Handle SNS binding conflict
    showNotification(
      `This ${data.snsType} account is already bound to ${data.email}. ` +
        `Please use a different ${data.snsType} account or contact support.`
    );
  } else if (data.bindType === "address") {
    console.log("Address:", data.address);
    // Handle wallet address binding conflict
    showNotification(
      `This wallet address is already bound to ${data.email}. ` +
        `Please use a different wallet or contact support.`
    );
  }
});

TaskCompletedData Interface

typescript
interface TaskCompletedData {
  /** Task identifier */
  taskId: string;
  /** Task name/title */
  taskName: string;
  /** Task template identifier */
  templateId: string;
  /** The rewards of the task */
  rewards: TaskReward[];
}

interface TaskReward {
  /** Type of reward */
  rewardType: "Token" | "GTCPoints";
  /** Amount of reward */
  rewardAmount: string;
  /** Name of points/token (optional) */
  pointName?: string;
  /** Human readable reward description */
  rewardDescription: string;
  /** Token contract address (if applicable) */
  tokenAddress?: string;
  /** Blockchain network (if applicable) */
  tokenNetwork?: string;
}

BindConflictData Interface

typescript
interface BindConflictData {
  /** Email that the SNS or address is already bound to */
  email: string;
  /** Type of binding that failed */
  bindType: "sns" | "address";
  /** SNS type if bindType is "sns" */
  snsType?: SnsType;
  /** Address if bindType is "address" */
  address?: string;
}

type SnsType = "twitter" | "discord" | "telegram" | "reddit";

Complete Example

typescript
import { TaskOnEmbed } from "@taskon/embed";

const embed = new TaskOnEmbed({
  baseUrl: "https://taskon.xyz",
  containerElement: "#taskon-container",
  language: "en", // Initial language
  width: "100%",
  height: 600,
});

// Initialize the embed
await embed.init();

// Set up event listeners
embed.on("loginRequired", async () => {
  // Handle email login
  const email = "user@example.com";
  const isAuthorized = await embed.isAuthorized("Email", email);

  if (!isAuthorized) {
    const { signature, timestamp } = await fetch("/api/auth/sign", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ account: email }),
    }).then(r => r.json());

    await embed.login({
      type: "Email",
      account: email,
      signature,
      timestamp,
    });
  } else {
    await embed.login({
      type: "Email",
      account: email,
    });
  }
});

embed.on("routeChanged", fullPath => {
  console.log("Route changed to:", fullPath);
});

embed.on("taskCompleted", data => {
  console.log("Task completed:", data);

  // Analytics tracking
  analytics.track("task_completed", {
    task_id: data.taskId,
    task_name: data.taskName,
    rewards: data.rewards,
  });

  // Show success notification
  showNotification(`Congratulations! You completed "${data.taskName}"`);
});

embed.on("bindConflict", data => {
  // Handle binding conflicts
  const message =
    data.bindType === "sns"
      ? `This ${data.snsType} account is already linked to ${data.email}`
      : `This wallet address is already linked to ${data.email}`;

  showNotification(message, "error");
});

// Language switching example
const languageSelector = document.getElementById("language-selector");
languageSelector?.addEventListener("change", async event => {
  const selectedLanguage = (event.target as HTMLSelectElement).value;
  await embed.setLanguage(selectedLanguage);
  console.log(`Language switched to: ${selectedLanguage}`);
});

// Route navigation example
const navigateToProfile = () => {
  embed.setRoute("/profile");
};

// Dynamic size adjustment
const resizeEmbed = (width: string | number, height: string | number) => {
  embed.updateSize(width, height);
};

Released under the MIT License.