Skip to content

Per-Page Dynamic Questions

Overview

The per-page dynamic questions feature allows you to display different dynamic questions based on the current URL. This enables you to provide contextual, relevant questions to users depending on what page they're viewing.

Key Features

  • URL Pattern Matching: Define questions for specific pages using wildcard patterns
  • Order-Based Priority: First matching pattern wins (no complex priority numbers)
  • Multiple Modes: Whitelist, blacklist, or hybrid approaches
  • Backward Compatible: Existing configurations continue to work without changes
  • Auto-Conversion: Old format automatically converts to new format on-the-fly

Data Structure

Old Format (Still Supported)

{
  "en": ["question 1", "question 2", "question 3"],
  "fr": ["question 1", "question 2"]
}

This format shows the same questions on all pages.

New Format

{
  "en": {
    "default": ["general question 1", "general question 2"],
    "pages": [
      {
        "patterns": ["*/admin*", "*/dashboard*"],
        "questions": []
      },
      {
        "patterns": ["*/pricing*", "*/plans*"],
        "questions": ["Questions about pricing?", "Need help choosing a plan?"]
      },
      {
        "patterns": ["*/blog*", "*/articles*"],
        "questions": ["Looking for specific content?", "Need help finding an article?"]
      }
    ]
  }
}

Fields

  • default: Questions shown when no pattern matches (or empty array for whitelist mode)
  • pages (optional): Array of page-specific rules
  • patterns: Array of URL patterns to match (uses wildcard * syntax)
  • questions: Questions for this pattern (empty array [] = hide questions)

Pattern Matching

Pattern Syntax

Patterns use wildcard (*) syntax to match URLs:

  • "*/blog*" - Matches any URL containing /blog (e.g., /blog, /blog/post, /en/blog)
  • "*/pricing*" - Matches /pricing, /pricing/enterprise, /en/pricing
  • "*.example.com" - Matches any subdomain of example.com
  • "www.example.com/page*" - Matches specific paths on specific domain

Matching Logic

  1. Order Matters: Patterns are checked from top to bottom in the pages array
  2. First Match Wins: Stops at the first matching pattern
  3. Multiple Patterns Per Rule: A single rule can have multiple patterns (any match triggers the rule)
  4. No Match: If no pattern matches, uses default questions

Examples

{
  "en": {
    "default": ["General question"],
    "pages": [
      {
        "patterns": ["*/admin*"],
        "questions": []
      },
      {
        "patterns": ["*/*"],
        "questions": ["Catch-all question"]
      }
    ]
  }
}

Behavior: - /admin/settings → No questions (first match, empty array) - /about → "Catch-all question" (second match)

Important: Place more specific patterns before general ones!

Usage Modes

1. Whitelist Mode (Opt-In)

Show questions only on specific pages:

{
  "en": {
    "default": [],
    "pages": [
      {
        "patterns": ["*/pricing*"],
        "questions": ["Pricing question"]
      },
      {
        "patterns": ["*/support*"],
        "questions": ["Support question"]
      }
    ]
  }
}
  • Questions shown on /pricing and /support only
  • All other pages: no questions (default is empty)

2. Blacklist Mode (Opt-Out)

Show questions everywhere except specific pages:

{
  "en": {
    "default": ["General question"],
    "pages": [
      {
        "patterns": ["*/admin*", "*/internal*"],
        "questions": []
      }
    ]
  }
}
  • Questions shown on all pages
  • Except /admin and /internal pages (empty array hides questions)

3. Hybrid Mode (Mixed)

Default questions with page-specific overrides:

{
  "en": {
    "default": ["General question"],
    "pages": [
      {
        "patterns": ["*/pricing*"],
        "questions": ["Pricing-specific question"]
      },
      {
        "patterns": ["*/admin*"],
        "questions": []
      }
    ]
  }
}
  • /pricing → Pricing-specific questions
  • /admin → No questions
  • All other pages → General questions

Migration Guide

From Old Format to New Format

Before (Old Format):

{
  "en": ["question 1", "question 2"]
}

After (New Format - Equivalent):

{
  "en": {
    "default": ["question 1", "question 2"]
  }
}

No immediate migration needed! The old format continues to work. The system automatically treats old format as default questions.

Adding Per-Page Questions

Step 1: Keep existing questions as default:

{
  "en": {
    "default": ["existing question 1", "existing question 2"]
  }
}

Step 2: Add page-specific rules:

{
  "en": {
    "default": ["existing question 1", "existing question 2"],
    "pages": [
      {
        "patterns": ["*/pricing*"],
        "questions": ["Pricing-specific question"]
      }
    ]
  }
}

Best Practices

1. Order Your Patterns Carefully

Wrong: General patterns first

{
  "pages": [
    { "patterns": ["*/*"], "questions": ["Catch all"] },
    { "patterns": ["*/admin*"], "questions": [] }
  ]
}
The /admin* pattern will never match because */* matches first.

Correct: Specific patterns first

{
  "pages": [
    { "patterns": ["*/admin*"], "questions": [] },
    { "patterns": ["*/*"], "questions": ["Catch all"] }
  ]
}

Good: Group related pages

{
  "patterns": ["*/pricing*", "*/plans*", "*/billing*"],
  "questions": ["Questions about our pricing?"]
}

3. Test Your Patterns

Use the browser console to test patterns:

// Get questions for current page
import { getDynamicQuestions } from '@frontend/shared';
console.log(getDynamicQuestions('example.com', 'en', window.location.href));

4. Document Your Configuration

Add comments in your configuration management system:

{
  "comment": "Admin pages - hide questions to avoid distraction",
  "patterns": ["*/admin*"],
  "questions": []
}

Debugging

Enable Debug Logging

Dynamic questions include extensive debug logging. Check the browser console for:

  • 🔍 Current URL being matched
  • ✅ Pattern matched and rule index
  • 📋 Default questions used
  • 🚫 Questions explicitly hidden
  • 🔄 Old format auto-conversion

Common Issues

Issue: Questions not showing on a page

Solution: Check console logs: 1. Is the pattern matching? Look for "✅ Pattern matched" 2. Is the array empty? Look for "🚫 Questions explicitly hidden" 3. Is default empty? Look for "ℹ️ Default questions is empty (whitelist mode)"

Issue: Wrong questions showing

Solution: Check pattern order: 1. A more general pattern might be matching first 2. Reorder patterns to put specific ones first

Technical Details

Type Definitions

export interface DynamicQuestionPageRule {
  patterns: string[];
  questions: string[];
}

export interface DynamicQuestionsConfig {
  default: string[];
  pages?: DynamicQuestionPageRule[];
}

export type DynamicQuestions =
  | Record<string, string[]>                          // Old format
  | Record<string, DynamicQuestionsConfig>;           // New format

Pattern Matching Function

The system uses the existing matchesUrlPattern() function from urlUtils.ts:

matchesUrlPattern(url: string, pattern: string): boolean

This supports wildcard (*) matching with proper escaping.

Examples

E-commerce Site

{
  "en": {
    "default": ["How can we help you?"],
    "pages": [
      {
        "patterns": ["*/checkout*", "*/cart*"],
        "questions": []
      },
      {
        "patterns": ["*/products/*"],
        "questions": ["Questions about this product?", "Need sizing help?"]
      },
      {
        "patterns": ["*/category/*"],
        "questions": ["Looking for something specific?", "Need product recommendations?"]
      }
    ]
  }
}

SaaS Platform

{
  "en": {
    "default": ["Need help getting started?"],
    "pages": [
      {
        "patterns": ["*/app/*", "*/dashboard*"],
        "questions": []
      },
      {
        "patterns": ["*/pricing*"],
        "questions": ["Questions about our plans?", "Want to compare features?"]
      },
      {
        "patterns": ["*/docs/*"],
        "questions": ["Can't find what you're looking for?", "Need more detailed info?"]
      }
    ]
  }
}

Multi-Language Site

{
  "en": {
    "default": ["How can I help?"],
    "pages": [
      {
        "patterns": ["*/contact*"],
        "questions": ["Need to reach our team?"]
      }
    ]
  },
  "fr": {
    "default": ["Comment puis-je vous aider?"],
    "pages": [
      {
        "patterns": ["*/contact*"],
        "questions": ["Besoin de contacter notre équipe?"]
      }
    ]
  }
}

Support

For questions or issues with per-page dynamic questions:

  1. Check debug logs in browser console
  2. Verify pattern syntax with test cases
  3. Review this documentation for examples
  4. Contact the development team for assistance