User-centric widgets

Quick Start

Installation

Add the widget script to your HTML page:

<script src="https://cdn.jsdelivr.net/npm/fansunited-widgets-cdn@<version>/fu-widgets.iife.js"></script>

Important: Replace <version> with the latest version number. You can check the latest version on the npm registry page for fansunited-widgets-cdn. The current example uses version 0.0.82, but newer versions may be available.

Basic Configuration

Initialize the widget with required configuration:

FuWidget.init({
	fansUnited: {
		apiKey: "1111-333-your-fu-api-key",
		clientId: "your-client-id",
		environment: "prod", // "dev", "prod", "staging", "watg", "yolo"
		idSchema: "native",
		lang: "en", // Language code
		// Authentication options (choose one if needed):
		// tokenString: "your-auth-token", // Direct token authentication
		// tokenCookieName: "your-token-cookie-name", // Cookie-based authentication
	},
	firebase: {
		apiKey: "your-firebase-api-key",
		authDomain: "your-app.firebaseapp.com",
		projectId: "your-project-id",
		appId: "your-app-id",
	},
	language: "en", // Widget UI language
	urls: {
		classicQuizUrl: "/quiz/{CONTENT_ID}",
		personalityQuizUrl: "/personality-quiz/{CONTENT_ID}",
		eitherOrUrl: "/either-or/{CONTENT_ID}",
		pollUrl: "/poll/{CONTENT_ID}",
		matchQuizUrl: "/match-quiz/{CONTENT_ID}",
	},
	signInCTA: {
		defaultLabel: "Sign in to participate",
		onClick: () => {
			window.location.href = "/signin";
		},
		url: "https://yourdomain.com/signin", // Optional: Direct URL for the CTA
		target: "_self", // Optional: Link target (_self, _blank)
	},
	additionalCTA: {
		defaultLabel: "Learn More",
		onClick: () => {
			console.log("Additional CTA clicked");
		},
		url: "https://yourdomain.com/info", // Optional: Direct URL for the CTA
		target: "_blank", // Optional: Link target (_self, _blank)
	},
	playerOfTheMatch: {
		authRequirement: "REGISTERED", // Require authentication for POTM voting
	},
	// Additional configuration options
	imagePosition: "left", // "left" or "right" - Default image position for Polls and Quizzes
	showAnswerExplanations: true, // Show answer explanations in quiz widgets
	themeOptions: customThemeOptions, // Advanced theming options (see Theme Configuration section) for Polls and Quizzes
	defaultImagePlaceholderUrl: "https://example.com/placeholder.jpg", // Default placeholder image URL
});

Authentication Options

The widget supports multiple authentication methods for connecting to the Fans United API. The authentication methods are processed in the following order:

1. Direct Token Authentication

Provide a valid authentication token directly in the configuration:

FuWidget.init({
	fansUnited: {
		// ... other config
		tokenString: "your-auth-token", // Direct authentication token
	},
	// ... other config
});

This is the highest priority authentication method and will be used if provided.

2. Cookie-based Authentication

Use a token stored in a browser cookie:

FuWidget.init({
	fansUnited: {
		// ... other config
		tokenCookieName: "your-token-cookie-name", // Name of the cookie containing the token
	},
	// ... other config
});

The widget will look for a cookie with the specified name and use its value as the authentication token. This method is used if direct token authentication is not provided and the cookie exists.

3. Firebase Anonymous Authentication (Default)

If neither tokenString nor a valid tokenCookieName cookie is provided, the widget will fall back to Firebase anonymous authentication:

FuWidget.init({
	fansUnited: {
		// ... other config
	},
	firebase: {
		apiKey: "your-firebase-api-key",
		authDomain: "your-app.firebaseapp.com",
		projectId: "your-project-id",
		appId: "your-app-id",
	},
	// ... other config
});

This is the default authentication method and requires valid Firebase configuration.

Authentication Hierarchy

The widget follows this authentication hierarchy:

  1. If tokenString is provided, use it directly.
  2. If tokenString is not provided but tokenCookieName is, check for the cookie:
    • If the cookie exists, use its value as the token.
    • If the cookie does not exist, fall back to Firebase authentication.
  3. If neither tokenString nor tokenCookieName is provided, use Firebase authentication.

Note: When using tokenCookieName, the widget will automatically re-fetch the cookie value for each API request, ensuring it always uses the latest token value.

URL Configuration

The widget supports configuring URLs for different content types that will be used when a user clicks on an item in a list widget:

  • urls.classicQuizUrl: URL pattern for quiz content
  • urls.personalityQuizUrl: URL pattern for personality quiz content
  • urls.eitherOrUrl: URL pattern for either/or games
  • urls.pollUrl: URL pattern for polls
  • urls.matchQuizUrl: URL pattern for match quiz games

Each URL pattern should include the {CONTENT_ID} placeholder which will be replaced with the actual content ID when generating links.

Language Support

The widget supports multiple languages for both the UI and content:

  • language: Controls the widget UI language
  • fansUnited.lang: Controls the content language from Fans United API

Available languages for UI (language):

  • "bg" - Bulgarian
  • "en" - English
  • "ro" - Romanian
  • "pt" - Portuguese
  • "sr" - Serbian
  • "fr" - French
  • "de" - German
  • "it" - Italian
  • "fr-be" - Belgian French
  • "pl" - Polish
  • "pt-br" - Brazilian Portuguese
  • "el" - Greek

Available languages for content (fansUnited.lang):

  • "bg" - Bulgarian
  • "en" - English
  • "ro" - Romanian
  • "el" - Greek
  • "sk" - Slovak
  • "pt" - Portuguese
  • "sr" - Serbian
  • "hu" - Hungarian
  • "sv" - Swedish
  • "es" - Spanish
  • "fr" - French
  • "nl" - Dutch
  • "de" - German
  • "it" - Italian

Lead Collection Configuration

Lead collection in the widget follows a hierarchy of configurations, allowing for both global and content-specific settings.

Configuration Hierarchy

  1. Management Portal Configuration

    • Set in Management Portal under Configuration -> Auth Requirement
    • Enables/disables lead collection for specific content
    • Options: "FREE", "LEAD", "REGISTERED"
  2. Global Widget Configuration

    • Set during widget initialization
    • Applies to all content unless overridden
  3. HTML Attribute Configuration

    • Set per widget instance
    • Overrides global configuration

Example Configuration

  1. Enable leads in Management Portal:

    Configuration -> Auth Requirement -> LEAD
  2. Global configuration in widget initialization:

FuWidget.init({
	// ... other config
	leads: {
		defaultFields: ["fullName", "email"], // Default fields for all widgets
		position: "after", // Default position
		campaignId: "default-campaign", // Default campaign ID
		campaignName: "Default Campaign", // Default campaign name
		syncWithProfile: false, // Default profile synchronization setting
	},
});
  1. Individual widget configuration:
<div
    data-component="fu-widget"
    data-content-type="classic-quiz"
    data-content-id="quiz-123"
    data-lead-fields="firstName,lastName,email"  // Overrides defaultFields
    data-lead-position="before"                  // Overrides position
    data-campaign-id="summer-campaign"           // Overrides campaignId
    data-campaign-name="Summer Campaign 2024"    // Overrides campaignName
    data-lead-sync-with-profile="true"           // Overrides syncWithProfile (default: false)
></div>

Available Lead Fields

  • fullName - Full name input
  • firstName - First name input
  • lastName - Last name input
  • email - Email input
  • gender - Gender selection
  • country - Country selection
  • phoneCountryCode - Phone country code
  • phoneNumber - Phone number input

Lead Form Position

  • before - Lead form appears before content
  • after - Lead form appears after content

Profile Synchronization

The data-lead-sync-with-profile attribute controls whether anonymous user profiles are synchronized with the database after successful lead form submission. This feature is essential for displaying user names in leaderboards, tracking user participation across widgets, and enabling data export capabilities.

Supported Widgets:

  • Classic Quiz
  • Personality Quiz
  • Match Quiz
  • Poll
  • Collect Lead

Configuration Options

  • "true" - Enable profile synchronization
  • "false" - Disable profile synchronization (default)

Global Configuration

FuWidget.init({
	// ... other config
	leads: {
		// ... other lead config
		syncWithProfile: true, // Enable profile sync by default for all widgets
	},
});

Per-Widget Configuration

<div
	data-component="fu-widget"
	data-content-type="classic-quiz"
	data-content-id="quiz-123"
	data-lead-sync-with-profile="true"
></div>

Use Cases

Enable Profile Sync When:

  • You want to display user nicknames or names in leaderboards across multiple widgets
  • You plan to export user data for marketing campaigns
  • You need to analyze user behavior across different content types

Disable Profile Sync When:

  • You only need basic lead collection without user tracking
  • Privacy regulations require minimal data retention
  • You want to reduce database storage requirements
  • You're collecting leads for one-time campaigns only

Technical Details

When profile synchronization is enabled:

  • Anonymous user profiles are linked to the submitted lead information
  • User participation data is preserved across widget interactions
  • Export functionality can access complete user participation history

When profile synchronization is disabled:

  • Lead information is collected but not linked to user profiles
  • Each widget interaction is treated independently
  • Export functionality is limited to basic lead information

Important: Lead collection must be enabled in the Management Portal (Auth Requirement = "LEAD") for any lead collection configuration to take effect.

Sign-in CTA Configuration

The sign-in call-to-action (CTA) feature allows you to customize the label and click behavior for authentication prompts in widgets that require user sign-in. This is particularly useful for classic quiz, poll, and either-or widgets where users need to authenticate to participate.

The system automatically detects when a user is authenticated by fetching their profile using sdk.profile.getOwn().getInfo() and checking the anonymous property. Anonymous users are considered not authenticated and will see the sign-in CTA when required.

Configuration Hierarchy

The sign-in CTA configuration follows this priority order (highest to lowest):

  1. Data attributes - Widget-specific overrides
  2. Main config - Global defaults
  3. Translated defaults - Localized fallback values based on widget type
  4. Built-in defaults - Final fallback values

Global Configuration

Configure the sign-in CTA globally in your main widget configuration:

FuWidget.init({
	// ... other config
	signInCTA: {
		defaultLabel: "Sign in to participate",
		onClick: () => {
			// Your custom sign-in logic
			window.location.href = "/signin";
			// Or show a modal
			// showSignInModal();
			// Or trigger your authentication system
			// authService.showLogin();
		},
	},
});

Per-Widget Configuration

Override the sign-in CTA for specific widgets using data attributes:

<div
	data-component="fu-widget"
	data-content-type="classic-quiz"
	data-content-id="your-quiz-id"
	data-signin-cta-label="Join Now to Vote!"
	data-signin-cta-onclick="showCustomSignInModal()"
></div>

Configuration Options

signInCTA Object Properties

PropertyTypeRequiredDescription
defaultLabelstringNoThe text displayed on the sign-in button. If not provided, uses translated text based on widget type ("Sign in to play" for games, "Sign in to vote" for polls)
onClickfunctionNoFunction to execute when the sign-in button is clicked
urlstringNoDirect URL for the CTA link. Can be used instead of or in addition to onClick
targetstringNoLink target for the URL. Options: _self, _blank. Default: _self

additionalCTA Object Properties

The additionalCTA follows the same structure as signInCTA and can be used to add a secondary call-to-action button in widgets.

PropertyTypeRequiredDescription
defaultLabelstringNoThe text displayed on the additional CTA button
onClickfunctionNoFunction to execute when the additional CTA button is clicked
urlstringNoDirect URL for the CTA link. Can be used instead of or in addition to onClick
targetstringNoLink target for the URL. Options: _self, _blank. Default: _self

Data Attributes

Sign-in CTA:

AttributeDescriptionExample
data-signin-cta-labelOverride the button label for this widget"Join Now!"
data-signin-cta-onclickJavaScript code to execute on click"window.open('/signin', '_blank')"
data-signin-cta-urlDirect URL for the CTA link"https://yourdomain.com/signin"
data-signin-cta-targetLink target (_self, _blank, etc.)"_blank"

Additional CTA:

AttributeDescriptionExample
data-additional-cta-labelOverride the button label for this widget"Learn More"
data-additional-cta-onclickJavaScript code to execute on click"console.log('clicked')"
data-additional-cta-urlDirect URL for the CTA link"https://yourdomain.com/info"
data-additional-cta-targetLink target (_self, _blank)"_blank"

Authentication Detection

The widget system automatically determines user authentication status by:

  1. Fetching User Profile: Uses sdk.profile.getOwn().getInfo() when the SDK is available
  2. Checking Anonymous Status: Examines the anonymous property in the profile response
  3. Setting Authentication State: Users with anonymous: false are considered authenticated
  4. Reactive Updates: Authentication status is checked once and made available to all widgets

Use Cases

Redirect to Sign-in Page

signInCTA: {
	defaultLabel: "Sign In",
	url: '/login',
	target: '_self'
}

Or using onClick:

signInCTA: {
	defaultLabel: "Sign In",
	onClick: () => {
		window.location.href = '/login';
	}
}

Show Modal Dialog

signInCTA: {
	defaultLabel: "Login to Continue",
	onClick: () => {
		document.getElementById('signin-modal').style.display = 'block';
	}
}

Open Sign-in in New Tab

signInCTA: {
	defaultLabel: "Sign In",
	url: '/signin',
	target: '_blank'
}

Or using onClick:

signInCTA: {
	defaultLabel: "Sign In",
	onClick: () => {
		window.open('/signin', '_blank');
	}
}

Trigger Third-party Authentication

signInCTA: {
	defaultLabel: "Login with SSO",
	onClick: () => {
		// Trigger your authentication provider
		authProvider.login();
	}
}

Using Additional CTA

You can add a secondary call-to-action button alongside the sign-in CTA:

FuWidget.init({
	// ... other config
	signInCTA: {
		defaultLabel: "Sign In",
		url: '/signin',
		target: '_self'
	},
	additionalCTA: {
		defaultLabel: "Learn More",
		url: '/about',
		target: '_blank'
	}
});

Or configure it per widget using data attributes:

<div
	data-component="fu-widget"
	data-content-type="classic-quiz"
	data-content-id="your-quiz-id"
	data-additional-cta-label="View Rules"
	data-additional-cta-url="/rules"
	data-additional-cta-target="_blank"
></div>

NOTE: This is only supported in Classic Quiz, Poll, Personality Quiz and Match Quiz widgets.

Security Considerations

  • The data-signin-cta-onclick attribute executes JavaScript code, so ensure you trust the source
  • Validate and sanitize any user-provided onclick code in production environments
  • Consider using CSP (Content Security Policy) headers to restrict inline script execution

Authentication Requirements

Widgets support different authentication requirements that can be configured in the Management Portal:

Authentication Requirement Types

RequirementDescriptionSign-in CTA Behavior
null (None)No authentication requiredNever shown
"FREE"Just for fun, without authNever shown
"LEAD"Lead collection requiredNot shown (handled by lead collection)
"REGISTERED"User registration requiredShown to anonymous users

Supported Widgets

The following widgets support authentication requirements and will show the sign-in CTA when needed:

  • Classic Quiz Widget: Shows sign-in CTA instead of "Start Quiz" button (uses backend authRequirement)
  • Personality Quiz Widget: Shows sign-in CTA instead of "Start Quiz" button (uses backend authRequirement)
  • Either-Or Widget: Shows sign-in CTA instead of "Start" button (uses backend authRequirement)
  • Poll Widget: Shows sign-in CTA instead of voting options (uses backend authRequirement)
  • Player of the Match Widget: Shows sign-in CTA instead of vote buttons (uses configurable authRequirement)

Configuration

Authentication requirements are configured in the Management Portal for each piece of content. When set to "REGISTERED", the widget will:

  1. Check if the user is authenticated (not anonymous)
  2. Show the appropriate interface based on authentication status
  3. Allow authenticated users to participate immediately
  4. Prompt unauthenticated users to sign in first

Widget Types

Classic Quiz Widget

A quiz widget that presents questions with multiple choice answers.

<div
	data-component="fu-widget"
	data-content-type="classic-quiz"
	data-content-id="your-quiz-id"
	data-lead-fields="fullName,email"
	data-lead-position="after"
	data-lead-sync-with-profile="true"
	data-campaign-id="campaign-1"
	data-campaign-name="Summer Campaign"
	data-signin-cta-label="Join Now to Play!"
	data-signin-cta-onclick="showSignInModal()"
	data-layout-template="STANDARD"
	data-image-position="left"
	data-show-answer-explanations="true"
></div>

Configuration Attributes

AttributeDescriptionOptionsDefault
data-layout-templateVisual layout of the quiz"STANDARD", "SPLIT", "OVERLAY""STANDARD"
data-image-positionPosition of images in the quiz"left", "right"Config default
data-show-answer-explanationsShow explanations after answers"true", "false"Config default
data-lead-sync-with-profileSync anonymous profiles to database after lead submission"true", "false"Config default

Features

  • Multiple choice questions
  • Timer support
  • Score tracking
  • Results display
  • Prize support
  • Lead collection
  • Customizable sign-in CTA
  • Responsive design

Personality Quiz Widget

A personality quiz widget that presents questions to determine user personality traits or characteristics.

<div
	data-component="fu-widget"
	data-content-type="personality-quiz"
	data-content-id="your-personality-quiz-id"
	data-lead-fields="fullName,email"
	data-lead-position="after"
	data-lead-sync-with-profile="true"
	data-campaign-id="campaign-1"
	data-campaign-name="Summer Campaign"
	data-signin-cta-label="Join Now to Discover Your Personality!"
	data-signin-cta-onclick="showSignInModal()"
	data-layout-template="STANDARD"
	data-image-position="left"
></div>

Configuration Attributes

AttributeDescriptionOptionsDefault
data-layout-templateVisual layout of the personality quiz"STANDARD", "SPLIT", "OVERLAY""STANDARD"
data-image-positionPosition of images in the quiz"left", "right"Config default
data-lead-sync-with-profileSync anonymous profiles to database after lead submission"true", "false"Config default

Features

  • Personality assessment questions
  • Trait-based scoring system
  • Personalized results
  • Results sharing capabilities
  • Lead collection integration
  • Customizable sign-in CTA
  • Multiple layout templates
  • Prize support
  • Responsive design

Either/Or Widget

A game where users make quick decisions between two options.

Authentication Support: When the game's auth requirement is set to "REGISTERED" in the Management Portal, unauthenticated users will see a customizable sign-in CTA instead of the start button.

<div
	data-component="fu-widget"
	data-content-type="either-or"
	data-content-id="your-game-id"
	data-lead-fields="fullName,email"
	data-lead-position="after"
	data-campaign-id="campaign-1"
	data-campaign-name="Summer Campaign"
	data-signin-cta-label="Join the Game!"
	data-signin-cta-onclick="showSignInModal()"
></div>

Features

  • Quick decision gameplay
  • 3 lives system
  • Streak tracking
  • Leaderboard
  • Timer-based rounds
  • Personal best tracking
  • Customizable sign-in CTA
  • Prize support

Poll Widget

A widget for collecting user votes on various topics.

<div
	data-component="fu-widget"
	data-content-type="poll"
	data-content-id="your-poll-id"
	data-lead-fields="fullName,email"
	data-lead-position="after"
	data-lead-sync-with-profile="true"
	data-campaign-id="campaign-1"
	data-campaign-name="Summer Campaign"
	data-signin-cta-label="Vote Now - Sign In!"
	data-signin-cta-onclick="redirectToSignIn()"
	data-layout-template="STANDARD"
></div>

Configuration Attributes

AttributeDescriptionOptionsDefault
data-layout-templateVisual layout of the poll"STANDARD", "SPLIT", "OVERLAY""STANDARD"
data-lead-sync-with-profileSync anonymous profiles to database after lead submission"true", "false"Config default

Features

  • Single or multiple choice voting
  • Real-time results
  • Percentage visualization
  • Total votes tracking
  • Lead collection integration
  • Customizable sign-in CTA
  • Prize support

Match Quiz Widget

Interactive match prediction quiz that allows users to make predictions on various football match markets. Features multiple fixture types, real-time countdown timers, points system, and comprehensive result tracking with leaderboards.

<div
	data-component="fu-widget"
	data-content-type="match-quiz"
	data-content-id="your-match-quiz-id"
	data-lead-fields="fullName,email"
	data-lead-position="after"
	data-lead-sync-with-profile="true"
	data-campaign-id="campaign-1"
	data-campaign-name="Summer Campaign"
	data-signin-cta-label="Sign in to compete!"
	data-signin-cta-onclick="showSignInModal()"
	data-layout-template="STANDARD"
	data-image-position="left"
	data-show-countdown="true"
	data-show-team-labels="true"
	data-show-points="true"
	data-show-prediction-details="true"
></div>

Configuration Attributes

AttributeDescriptionOptionsDefault
data-layout-templateVisual layout of the match quiz"STANDARD", "SPLIT", "OVERLAY""STANDARD"
data-image-positionPosition of images in the quiz"left", "right"Config default
data-show-countdownShow countdown timer when Match Quiz is open"true", "false""false"
data-show-team-labelsShow team name labels in fixture components"true", "false""true"
data-show-pointsShow points display for each fixture"true", "false""false"
data-show-prediction-detailsShow detailed prediction results after completion"true", "false""false"
data-lead-sync-with-profileSync anonymous profiles to database after lead submission"true", "false"Config default

Features

  • Multiple prediction markets (1X2, Correct Score, Player Markets, Over/Under Goals, Corners, etc.)
  • Real-time countdown timer for prediction cutoff
  • Points system with loyalty integration
  • Leaderboard and ranking system
  • Prediction summary and editing capabilities
  • Three responsive templates (Standard, Split, Overlay)
  • Lead collection integration
  • Authentication support
  • Custom theming and branding
  • Detailed prediction results and explanations

Supported Markets

MatchQuiz supports a wide variety of football prediction markets:

Match Result Markets:

  • FT_1X2 - Full Time 1X2 (Home Win, Draw, Away Win)
  • HT_1X2 - Half Time 1X2

Score Markets:

  • CORRECT_SCORE - Exact final score prediction
  • CORRECT_SCORE_HT - Exact half-time score prediction
  • CORRECT_SCORE_ADVANCED - Advanced correct score with alternative points

Player Markets:

  • PLAYER_SCORE_FIRST_GOAL - First goalscorer prediction
  • PLAYER_SCORE - Anytime goalscorer
  • PLAYER_YELLOW_CARD - Player to receive yellow card
  • PLAYER_RED_CARD - Player to receive red card
  • PLAYER_SCORE_HATTRICK - Player to score hat-trick
  • PLAYER_SCORE_TWICE - Player to score twice

Over/Under Markets:

  • OVER_GOALS_0_5 to OVER_GOALS_6_5 - Total goals over/under
  • OVER_CORNERS_6_5 to OVER_CORNERS_13_5 - Total corners over/under

Special Markets:

  • CORNERS_MATCH - Total corners in the match
  • PENALTY_MATCH - Penalty awarded in the match
  • RED_CARD_MATCH - Red card shown in the match

Game Status States

Match quizzes have 5 distinct status states:

  • PENDING - Not yet open for predictions
  • OPEN - Ready for predictions (default state)
  • LIVE - Match has started, no new predictions accepted
  • CLOSED - Match finished, backend resolving predictions
  • SETTLED - Predictions resolved, leaderboard available

Authentication and Sign-in

When the match quiz's auth requirement is set to "REGISTERED" in the Management Portal, unauthenticated users will see a customizable sign-in CTA instead of the quiz interface. The sign-in behavior can be configured globally or per-widget using the data-signin-cta-label and data-signin-cta-onclick attributes.

Collect Lead Widget

A dedicated widget for collecting user information and leads without requiring other content interaction.

<div
	data-component="fu-widget"
	data-content-type="collect-lead"
	data-content-id="your-lead-form-id"
	data-content-name="Newsletter Signup"
	data-lead-fields="fullName,email,phoneNumber"
	data-lead-sync-with-profile="true"
	data-campaign-id="newsletter-campaign"
	data-campaign-name="Newsletter Campaign 2024"
	data-layout-template="STANDARD"
	data-image-position="left"
	data-images='{"main":"https://example.com/image.jpg"}'
	data-branding='{"logo":"https://example.com/logo.png","link":"https://example.com"}'
	data-onsuccess-label="Continue Reading"
	data-onsuccess-url="https://example.com/thank-you"
	data-onsuccess-target="_blank"
	data-labels='{"leadTitle":"Join Our Newsletter","leadDescription":"Get the latest updates"}'
	data-custom-fields='[{"key":"interests","required":false,"label":"Interests","type":"textarea"}]'
	data-consents='[{"key":"marketing","required":true,"label":"Marketing consent","privacyPolicyUrl":"https://example.com/privacy"}]'
></div>

Configuration Attributes

AttributeDescriptionOptions/FormatDefault
data-content-nameName/title for the lead formAny stringNone
data-lead-fieldsFields to display in the formComma-separated field namesConfig default
data-lead-sync-with-profileSync anonymous profiles to database after lead submission"true", "false"Config default
data-layout-templateVisual layout of the form"STANDARD", "SPLIT", "OVERLAY""STANDARD"
data-image-positionPosition of images in the form"left", "right"Config default
data-imagesJSON object with image URLs{"main":"url","cover":"url"}None
data-brandingJSON object with branding info{"logo":"url","link":"url"}None
data-onsuccess-labelSuccess CTA button labelAny stringNone
data-onsuccess-urlSuccess CTA redirect URLValid URLNone
data-onsuccess-targetSuccess CTA link target"_blank", "_self", "_parent""_self"
data-onsuccess-onclickSuccess CTA JavaScript functionJavaScript codeNone
data-labelsJSON object with custom labels{"leadTitle":"text","leadCta":"text"}None
data-custom-fieldsJSON array of custom form fieldsArray of field objectsNone
data-consentsJSON array of consent checkboxesArray of consent objectsNone

Features

  • Standalone lead collection form
  • Configurable form fields
  • Custom branding support
  • Success call-to-action options
  • Custom field support
  • Consent management
  • Multiple layout templates
  • Image positioning
  • Responsive design
  • Campaign tracking

Custom Fields Format

Custom fields can be added using the data-custom-fields attribute with the following format:

[
  {
    "key": "field-key",
    "required": true,
    "label": "Field Label",
    "type": "input",
    "placeholder": "Enter value"
  },
  {
    "key": "textarea-field",
    "required": false,
    "label": "Comments",
    "type": "textarea",
    "placeholder": "Enter comments"
  }
]

Consents Format

Consent checkboxes can be added using the data-consents attribute:

[
  {
    "key": "marketing",
    "required": true,
    "label": "I agree to receive marketing communications",
    "privacyPolicyUrl": "https://example.com/privacy",
    "privacyPolicyUrlLabel": "Privacy Policy",
    "termsAndConditionsUrl": "https://example.com/terms",
    "termsAndConditionsUrlLabel": "Terms and Conditions"
  }
]

List Widget

A widget that displays a collection of different content types.

<div
	data-component="fu-widget"
	data-content-type="list"
	data-content-id="your-list-id"
	data-classic-quiz-url="/quiz/{CONTENT_ID}/custom-path"
	data-personality-quiz-url="/personality-quiz/{CONTENT_ID}/custom-path"
	data-either-or-url="/either-or/{CONTENT_ID}/custom-path"
	data-poll-url="/poll/{CONTENT_ID}/custom-path"
	data-match-quiz-url="/match-quiz/{CONTENT_ID}/custom-path"
	data-items-count="10"
	data-items-per-row="2"
	data-widget-mode="LOAD_MORE"
></div>

Configuration Attributes

AttributeDescriptionOptions/FormatDefault
data-classic-quiz-urlCustom URL pattern for quiz contentURL with {CONTENT_ID} placeholderGlobal config
data-personality-quiz-urlCustom URL pattern for personality quiz contentURL with {CONTENT_ID} placeholderGlobal config
data-either-or-urlCustom URL pattern for either/or gamesURL with {CONTENT_ID} placeholderGlobal config
data-poll-urlCustom URL pattern for pollsURL with {CONTENT_ID} placeholderGlobal config
data-match-quiz-urlCustom URL pattern for match quiz gamesURL with {CONTENT_ID} placeholderGlobal config
data-items-countNumber of items to displayPositive integer10
data-items-per-rowItems per row in grid layoutPositive integer2
data-widget-modeList display mode"LOAD_MORE", "LIMITED""LOAD_MORE"

URL Configuration

You can specify URL patterns for each content type in the list widget either through global configuration (in the initialization) or through HTML attributes. These URL patterns should include {CONTENT_ID} which will be replaced with the actual content ID when generating links. HTML attributes will override the global URL configuration.

Widget Modes

  • LOAD_MORE: Shows items with a "Load More" button to fetch additional content
  • LIMITED: Shows exactly the specified number of items without load more functionality

Features

  • Mixed content display of different widget types
  • Responsive grid layout
  • Click-through navigation to individual content items
  • Dynamic loading
  • Support for all widget content types

Match Prediction Widget

The Match Prediction widget allows users to make predictions on specific markets for a match, showing real-time community prediction statistics.

<div data-component="fu-widget" data-content-type="match-prediction" data-content-id="your-match-id" data-market="FT_1X2"></div>

Features

  • Multiple prediction markets support
  • Real-time community prediction statistics
  • Visual display of prediction percentages
  • 1X2 (home, draw, away) predictions
  • Yes/No market predictions
  • Success notification feedback
  • Team logo and name display

Configuration

  • data-content-id: Match ID for which predictions will be made
  • data-market: The prediction market to display (optional, defaults to "FT_1X2")

Supported Markets

  • 1X2 Markets

    • FT_1X2 - Full-time match result (Home win, Draw, Away win)
    • HT_1X2 - Half-time match result
  • Yes/No Markets

    • BOTH_TEAMS_SCORE - Whether both teams will score
    • PENALTY_MATCH - Whether there will be a penalty in the match
    • RED_CARD_MATCH - Whether there will be a red card in the match

Team Next Match Prediction Widget

The Team Next Match Prediction widget automatically identifies the team's upcoming match and allows users to make predictions.

<div data-component="fu-widget" data-content-type="team-next-match-prediction" data-content-id="your-team-id" data-market="FT_1X2"></div>

Features

  • Automatically fetches team's next scheduled match
  • All prediction markets supported by the Match Prediction widget
  • Community prediction statistics
  • Success notification feedback
  • Team logo and name display

Configuration

  • data-content-id: Team ID to find the next match for
  • data-market: The prediction market to display (optional, defaults to "FT_1X2")

Implementation Tips

  • This widget is ideal for team pages where you want to show the next upcoming match
  • Saves the effort of manually updating match IDs as fixtures change
  • The available markets depend on the league/competition of the team's upcoming match

Player of the Match Widget

The Player of the Match widget allows users to vote for the best player in a football match, see real-time voting results, and view the final winner after voting ends.

<div
	data-component="fu-widget"
	data-content-type="player-of-the-match"
	data-content-id="your-match-id"
	data-voting-window="2"
	data-potm-auth-requirement="REGISTERED"
	data-signin-cta-label="Sign in to vote!"
	data-signin-cta-onclick="showSignInModal()"
	data-show-team="team_id"
	data-show-players="player1_id,player2_id,player3_id"
	data-branded-area-image="https://example.com/sponsor-logo.png"
	data-branded-area-link="https://sponsor-website.com"
></div>

Features

  • Interactive carousel display of all players from both teams
  • Team filtering to quickly find players
  • Real-time voting and results
  • Countdown timer for upcoming matches
  • Visual display of the match context and teams
  • Winner announcement after voting period ends
  • Ability to change or remove votes
  • Configurable authentication requirements
  • Customizable sign-in CTA for unauthenticated users
  • Responsive design for all devices
  • Support for all positions and player types

Configuration Attributes

AttributeDescriptionOptions/FormatDefault
data-content-idMatch ID for votingMatch ID stringRequired
data-voting-windowHours after match end for voting0-168 (hours)1
data-potm-auth-requirementAuthentication requirement"REGISTERED" or omitNone
data-signin-cta-labelCustom sign-in button labelAny stringTranslated default
data-signin-cta-onclickCustom sign-in actionJavaScript codeNone
data-show-teamFilter players by team IDTeam ID string"all"
data-show-playersShow specific players onlyComma-separated player IDsAll players
data-branded-area-imageSponsor logo URLImage URLNone
data-branded-area-linkSponsor link URLWebsite URLNone

Player Display and Sorting

Players are displayed in a carousel format and sorted by:

  • Vote count (highest votes first)
  • When filtered by team, maintains the vote count sorting within that team's players

States

The widget has three main states:

  1. Upcoming Match

    • Displays countdown to match start
    • Voting not yet available
  2. Active Voting

    • Shows interactive player carousel
    • Allows selecting and voting for players
    • Displays real-time vote counts
  3. Voting Ended

    • Shows the top three players with vote percentages
    • Highlights the winner with a trophy icon
    • Displays final vote distribution

Implementation Tips

  • Place the widget on match pages for immediate context
  • Works best with matches that have confirmed lineups
  • The voting window parameter can be adjusted based on your audience engagement patterns
  • For high-traffic sites, a shorter voting window (1-2 hours) creates more urgency
  • For lower traffic, consider extending the window (24-48 hours) to gather more votes

Common Market Types

Both prediction widgets support various market types that can be specified using the data-market attribute.

1X2 Markets

For 1X2 markets, the widget displays three prediction options: Home win, Draw, and Away win.

Supported 1X2 markets:

  • FT_1X2 - Full-time match result (default)
  • HT_1X2 - Half-time match result

Yes/No Markets

For Yes/No markets, the widget displays two prediction options: Yes and No.

Supported Yes/No markets:

  • BOTH_TEAMS_SCORE - Whether both teams will score
  • PENALTY_MATCH - Whether there will be a penalty in the match
  • RED_CARD_MATCH - Whether there will be a red card in the match

Other Available Markets

Additional markets are available depending on your implementation needs. These include:

  • Player-specific markets (PLAYER_SCORE, PLAYER_YELLOW_CARD, etc.)
  • Over/under markets
  • Correct score markets

Note: Some markets may be unavailable for certain competitions or matches, depending on data provider coverage.

Configuration Options

Authentication Configuration

The fansUnited section of the configuration supports the following authentication options:

fansUnited: {
    // ... other config
    tokenString: "your-auth-token", // Direct token authentication
    tokenCookieName: "your-token-cookie-name", // Cookie-based authentication
}
  • tokenString: A direct authentication token to use for API requests.
  • tokenCookieName: The name of a cookie that contains an authentication token.

Implementation Priority: The widget first checks for tokenString, then tokenCookieName, and finally falls back to Firebase anonymous authentication.

Theme Configuration

Basic Theme Configuration

This is the legacy configuration available to all widgets with the exception of Polls and Quizzes.

theme: {
    mode: "light", // "light" or "dark"
    primaryColor: {
        50: "#ebfff3",
        100: "#d1ffe4",
        200: "#a3ffc8",
        300: "#66f59d",
        400: "#2ce97a",
        500: "#0cd664",
        600: "#09b954",
        700: "#078f42",
        800: "#056b31",
        900: "#034d23",
    }
}

Advanced Theme Configuration with themeOptions

This configuration is available for Polls and Quizzes only. As we roll out updates for other widgets, we will be deprecating the theme configuration in favor of themeOptions. For more comprehensive theming, use the themeOptions configuration:

import { CustomThemeOptions } from "fansunited-frontend-core";

// Default theme options
const themeOptions: CustomThemeOptions = {
  mode: "light", // or 'dark'
  colorSchemes: {
    light: {
      palette: {
        success: {
          plainColor: "#4CAF50",
          outlinedBorder: "#4CAF50",
        },
        danger: {
          softBg: "#FEE4E2",
          plainColor: "#F44336",
          outlinedBorder: "#F44336",
        },
        primary: {
          plainColor: "#1A77D2",
          outlinedBorder: "#1A77D2",
          onPrimary: "#FAFAFA",
          primaryContainer: "#2397F3",
        },
        warning: {
          softBg: "#FEF0C7",
          plainColor: "#DC6803",
        },
      },
      textPrimary: "#212121",
      textSecondary: "#212121",
      textColor: "#212121",
      textDisabled: "#212121",
      surface: "#FFFFFF",
      onSurface: "#F5F5F5",
      surfaceVariant: "#EEEEEE",
      surfaceTintDim: "#212121",
      surfaceInverse: "#F5F5F5",
      outlineEnabledBorder: "#E0E0E0",
      secondaryContainer: "#BDBDBD",
    },
    dark: {
      palette: {
        primary: {
          plainColor: "#1A77D2",
          outlinedBorder: "#1A77D2",
          onPrimary: "#FAFAFA",
          primaryContainer: "#2397F3",
        },
        success: {
          plainColor: "#4CAF50",
          outlinedBorder: "#4CAF50",
        },
        danger: {
          softBg: "#430A0A",
          plainColor: "#F44336",
          outlinedBorder: "#F44336",
        },
        warning: {
          softBg: "#FEF0C7",
          plainColor: "#DC6803",
        },
      },
      textPrimary: "#FAFAFA",
      textSecondary: "#FAFAFA",
      textColor: "#FAFAFA",
      textDisabled: "#FAFAFA",
      surface: "#424242",
      onSurface: "#212121",
      surfaceVariant: "#616161",
      surfaceTintDim: "#FAFAFA",
      surfaceInverse: "#FAFAFA",
      outlineEnabledBorder: "#757575",
      secondaryContainer: "#757575",
    },
  },
  customBreakpoints: {
    values: {
      xs: 0,
      sm: 444,
      md: 600,
      lg: 900,
      xl: 1200,
      xxl: 1536,
    },
  },
  spacingScale: {
    "3xs": "2px",
    "2xs": "4px",
    xs: "8px",
    sm: "12px",
    md: "16px",
    lg: "24px",
    xl: "32px",
    "2xl": "40px",
    "3xl": "48px",
  },
  customFontFamily: {
    light: {
      primary: "Ubuntu, sans-serif",
      secondary: "Roboto, sans-serif",
    },
    dark: {
      primary: "Ubuntu, sans-serif",
      secondary: "Roboto, sans-serif",
    },
  },
  customRadius: {
    light: {
      none: "0px",
      "2xs": "2px",
      xs: "4px",
      sm: "8px",
      md: "12px",
      lg: "16px",
      xl: "24px",
      "2xl": "232px",
      full: "1000px",
    },
    dark: {
      none: "0px",
      "2xs": "2px",
      xs: "4px",
      sm: "8px",
      md: "12px",
      lg: "16px",
      xl: "24px",
      "2xl": "232px",
      full: "1000px",
    },
  },
  border: {
    light: {
      size: "1px",
    },
    dark: {
      size: "2px",
    },
  },
  imageBackgroundGradient: {
    light: {
      standard:
        "linear-gradient(270deg, rgba(255, 255, 255, 0) 0%, rgba(18, 18, 18, 0.8) 100%)",
      split:
        "linear-gradient(270deg, rgba(255, 255, 255, 0) 0%, rgba(18, 18, 18, 0.8) 100%)",
    },
    dark: {
      standard:
        "linear-gradient(270deg, rgba(255, 255, 255, 0) 0%, rgba(18, 18, 18, 0.8) 100%)",
      split:
        "linear-gradient(270deg, rgba(255, 255, 255, 0) 0%, rgba(18, 18, 18, 0.8) 100%)",
      overlay:
        "linear-gradient(270deg, rgba(255, 255, 255, 0) 0%, rgba(18, 18, 18, 0.8) 100%)",
    },
  },
};

FuWidget.init({
    // ... other config
    themeOptions: themeOptions,
});

Content Labels

Custom labels can be set for each content piece from the management portal under the Labels configuration:

Prize Labels

  • prizeCardTitle - Title of the prize card
  • prizeCardDescription - Description in the prize card
  • prizeCta - Call to action for prize details

Lead Form Labels

  • leadTitle - Title of the lead form
  • leadDescription - Description text for lead collection
  • leadCta - Submit button text
  • leadSuccessTitle - Success message title
  • leadSuccessDescription - Success message description

Score Message Labels

  • scoreMessagePerfect - Override the default message when a user gets a perfect score.
  • scoreMessageAmazing - Override the default message when a user gets 80+%.
  • scoreMessageWellDone - Override the default message when a user gets 60+%.
  • scoreMessageGoodEffort - Override the default message when a user gets 40+%.
  • scoreMessageKeepGoing - Override the default message when a user gets less than 40%.

Display Configuration

The widget supports the following display configuration options:

FuWidget.init({
	// ... other config
	displayPlayNextSection: true, // Show/hide "Play Next" section (default: true)
	displayQuizDescription: true, // Show/hide quiz description (default: true)
	defaultImagePlaceholderUrl: "https://example.com/placeholder.jpg", // Default placeholder image URL
});
  • displayPlayNextSection: Controls the visibility of the "Play Next" section in quiz widgets (default: true)
  • displayQuizDescription: Controls the visibility of quiz descriptions (default: true)
  • defaultImagePlaceholderUrl: An optional URL for the default placeholder image used when content images fail to load or are not available

These options can also be set on individual widget instances:

<div
	data-component="fu-widget"
	data-content-type="classic-quiz"
	data-content-id="quiz-123"
	data-display-play-next-section="false"
	data-display-quiz-description="false"
	data-default-image-placeholder-url="https://example.com/custom-placeholder.jpg"
></div>

Widget Refresh Method

For Single Page Applications (SPAs) or dynamic content scenarios where widgets need to be reinitialized after navigation or content changes, you can use the refresh method:

// Manually refresh all widgets on the page
FuWidget.refresh();

When to Use Widget Refresh

  • SPA Navigation: After navigating to a new page that contains widgets
  • Dynamic Content Loading: When new widget elements are added to the DOM via JavaScript
  • Content Updates: When widget content IDs or configurations change dynamically
  • Error Recovery: To reinitialize widgets after network errors or other issues

Implementation Example

// Example for SPA router
router.on("route-changed", () => {
	// Small delay to ensure DOM is updated
	setTimeout(() => {
		FuWidget.refresh();
	}, 100);
});

// Example for dynamic content loading
function loadNewContent() {
	fetch("/api/content")
		.then((response) => response.text())
		.then((html) => {
			document.getElementById("content").innerHTML = html;
			// Refresh widgets after new content is loaded
			FuWidget.refresh();
		});
}

Important Notes

  • The refresh method will reinitialize ALL widgets on the page
  • Existing widget state will be lost during refresh
  • Only call refresh when necessary to avoid performance issues
  • Widgets automatically prevent double initialization, so calling refresh multiple times is safe

Language Support

The FU Widget system supports multiple languages for all widget types. Each widget displays content in the language specified in the configuration.

Available Languages

All widgets support the following languages:

  • English (en)
  • Bulgarian (bg)
  • Romanian (ro)
  • Portuguese (pt)
  • Serbian (sr)
  • French (fr)
  • German (de)
  • Italian (it)
  • Belgian French (fr-be)
  • Polish (pl)
  • Brazilian Portuguese (pt-br)
  • Greek (el)

Browser Support

  • Chrome (latest 2 versions)
  • Firefox (latest 2 versions)
  • Safari (latest 2 versions)
  • Edge (latest 2 versions)
  • iOS Safari (latest 2 versions)
  • Android Chrome (latest 2 versions)