Frequency Rules
Control announcement display frequency with once, daily, weekly, and session-based rules to avoid notification fatigue
Frequency Rules
Control how often users see announcements with flexible frequency rules. Rules are enforced automatically and state is persisted across sessions.
Why Frequency Rules?
Prevent announcement fatigue by controlling when and how often announcements appear:
- Respect users - Don't show the same announcement repeatedly
- Optimize engagement - Show announcements at the right frequency
- Track views - Know how many times users have seen each announcement
- Persistent state - Frequency rules persist across sessions
Frequency Types
type FrequencyRule =
| 'once' // Only ever show once
| 'session' // Once per session
| 'always' // Every time
| { type: 'times'; count: number } // N times total
| { type: 'interval'; days: number } // Every N daysOnce
Show the announcement only one time ever:
{
id: 'welcome',
variant: 'modal',
title: 'Welcome to Our App',
frequency: 'once', // Shows once, then never again
}Use for:
- Welcome messages
- One-time feature introductions
- Privacy policy updates
- Terms acceptance
State is persisted to localStorage by default, so "once" means once across all sessions.
Session
Show once per browser session:
{
id: 'tip-of-day',
variant: 'toast',
title: 'Daily Tip',
frequency: 'session', // Shows once per session
}Use for:
- Session-specific tips
- Temporary notices
- Per-visit reminders
A new session starts when:
- User closes all browser tabs
- Session storage is cleared
- Browser is restarted
Always
Show every time the announcement is eligible:
{
id: 'critical-alert',
variant: 'banner',
title: 'System Maintenance in Progress',
frequency: 'always', // Shows every time
}Use for:
- Critical system alerts
- Real-time status updates
- Urgent notifications
- Temporary announcements
Use always sparingly. It can lead to announcement fatigue if overused.
Times
Show N times total, then stop:
{
id: 'feature-promo',
variant: 'slideout',
title: 'Try Our New Feature',
frequency: { type: 'times', count: 3 }, // Show 3 times total
}Use for:
- Feature promotions (show a few times)
- Gradual onboarding (spread over multiple visits)
- Survey invitations
- Feedback requests
Example
const announcements = [
{
id: 'survey',
variant: 'modal',
title: 'We Value Your Feedback',
description: 'Take our 2-minute survey to help us improve.',
frequency: {
type: 'times',
count: 2, // Show twice, then stop
},
primaryAction: {
label: 'Take Survey',
onClick: () => window.open('/survey'),
},
onShow: () => {
// Track which view this is
const announcement = useAnnouncement('survey');
analytics.track('survey_shown', {
viewNumber: announcement.viewCount,
});
},
},
];Interval
Show every N days:
{
id: 'weekly-update',
variant: 'banner',
title: 'Weekly Product Update',
frequency: { type: 'interval', days: 7 }, // Show every 7 days
}Use for:
- Periodic updates
- Weekly tips
- Monthly reminders
- Recurring promotions
Examples
// Show every day
frequency: { type: 'interval', days: 1 }
// Show every week
frequency: { type: 'interval', days: 7 }
// Show every 2 weeks
frequency: { type: 'interval', days: 14 }
// Show every month (approx)
frequency: { type: 'interval', days: 30 }How It Works
The interval starts from the last time the announcement was shown:
// First view: Today at 10:00 AM
// Next eligible: 7 days later at 10:00 AM
// If dismissed before 7 days, won't show until interval passesCombining with Dismissal
Frequency rules work with dismissal patterns:
{
id: 'promo',
variant: 'toast',
title: 'Limited Time Offer',
frequency: { type: 'interval', days: 3 }, // Show every 3 days
// If user dismisses, they won't see it again
// If user just hides it, it will show again in 3 days
}Dismiss vs Hide
- Dismiss - Permanently removes the announcement (ignores frequency)
- Hide - Temporarily hides, respects frequency rules
import { useAnnouncement } from '@tour-kit/announcements';
function AnnouncementControls() {
const announcement = useAnnouncement('promo');
return (
<div>
{/* Hide - will show again based on frequency */}
<button onClick={announcement.hide}>
Remind Me Later
</button>
{/* Dismiss - won't show again */}
<button onClick={() => announcement.dismiss()}>
Don't Show Again
</button>
</div>
);
}Checking Eligibility
Use canShow to check if an announcement can be shown:
import { useAnnouncement } from '@tour-kit/announcements';
function SmartTrigger() {
const announcement = useAnnouncement('feature-tip');
useEffect(() => {
// Only show if frequency rules allow
if (announcement.canShow) {
announcement.show();
}
}, []);
}View Tracking
Track how many times an announcement has been viewed:
import { useAnnouncement } from '@tour-kit/announcements';
function ViewCounter() {
const announcement = useAnnouncement('tip');
return (
<div>
<p>Viewed {announcement.viewCount} times</p>
<p>Can show: {announcement.canShow ? 'Yes' : 'No'}</p>
{announcement.state.lastViewedAt && (
<p>
Last viewed:{' '}
{announcement.state.lastViewedAt.toLocaleDateString()}
</p>
)}
</div>
);
}Advanced Patterns
Reset After Completion
{
id: 'onboarding',
variant: 'modal',
title: 'Complete Onboarding',
frequency: 'once',
primaryAction: {
label: 'Complete',
onClick: () => {
completeOnboarding();
announcement.complete();
// User completed - won't see again
},
},
secondaryAction: {
label: 'Skip',
onClick: () => {
announcement.hide();
// User skipped - can see again next session
},
},
}Conditional Frequency
const getFrequency = (userPlan: string): FrequencyRule => {
// Free users see promo every 3 days
if (userPlan === 'free') {
return { type: 'interval', days: 3 };
}
// Pro users see once
return 'once';
};
const announcements = [
{
id: 'upgrade-promo',
variant: 'banner',
title: 'Upgrade to Pro',
frequency: getFrequency(user.plan),
},
];Progressive Disclosure
Show different announcements based on view count:
function ProgressiveAnnouncements() {
const welcome = useAnnouncement('welcome');
const advanced = useAnnouncement('advanced-tips');
useEffect(() => {
// Show welcome first 3 times
if (welcome.viewCount < 3 && welcome.canShow) {
welcome.show();
}
// Then show advanced tips
else if (welcome.viewCount >= 3 && advanced.canShow) {
advanced.show();
}
}, [welcome.viewCount]);
}Storage
Frequency state is persisted using the storage option:
<AnnouncementsProvider
storage="localStorage" // Default - persists across sessions
// storage="sessionStorage" // Session only
// storage="memory" // Not persisted
/>Stored Data
{
"announcement-id": {
"viewCount": 2,
"lastViewedAt": "2024-01-20T10:30:00Z",
"isDismissed": false
}
}TypeScript
import type { FrequencyRule } from '@tour-kit/announcements';
const onceRule: FrequencyRule = 'once';
const sessionRule: FrequencyRule = 'session';
const alwaysRule: FrequencyRule = 'always';
const timesRule: FrequencyRule = {
type: 'times',
count: 5,
};
const intervalRule: FrequencyRule = {
type: 'interval',
days: 7,
};Related
- AnnouncementsProvider - Configure storage
- useAnnouncement - Access view count and eligibility
- Audience Targeting - Target specific users