react-native-content-filtering-webview
v1.0.8
Published
React Native WebView with native content filtering support (WKContentRuleList on iOS, request interception on Android)
Maintainers
Readme
react-native-content-filtering-webview
A React Native WebView component with native content filtering support. Uses WKContentRuleList on iOS for efficient native filtering and request interception on Android.
Features
- Native iOS Content Blocking: Uses WKContentRuleList (same technology as Safari Content Blockers) for efficient, native-level filtering
- Android Request Interception: Intercepts and blocks requests at the native level
- Domain Whitelisting: Only allow resources from specific domains
- Domain Blacklisting: Block resources from specific domains
- Third-Party Blocking: Block all third-party requests
- Resource Type Filtering: Block specific resource types (scripts, images, etc.)
- HTTPS Upgrade: Automatically upgrade HTTP requests to HTTPS
- CSS Element Hiding: Hide elements on the page using CSS selectors
- Rule Validation: Validate rules before compilation to catch errors early
- Safari Content Blocker Format: Uses the standard Safari Content Blocker JSON format
Installation
npm install react-native-content-filtering-webview react-native-webview
# or
yarn add react-native-content-filtering-webview react-native-webviewiOS
cd ios && pod installAndroid
No additional setup required - the module auto-links.
Quick Start
Using Presets (Simple)
The easiest way to use content filtering is with presets:
import { ContentFilteringWebView } from 'react-native-content-filtering-webview';
// Only allow content from specific domains
<ContentFilteringWebView
source={{ uri: 'https://example.com' }}
contentFilterPreset={{
allowedDomains: ['example.com', 'cdn.example.com'],
}}
/>
// Block ads and trackers
<ContentFilteringWebView
source={{ uri: 'https://example.com' }}
contentFilterPreset={{
blockedDomains: ['ads.example.com', 'tracker.example.com'],
blockThirdParty: true,
}}
/>
// Block specific resource types
<ContentFilteringWebView
source={{ uri: 'https://example.com' }}
contentFilterPreset={{
blockedResourceTypes: ['script', 'popup'],
}}
/>Using Custom Rules (Advanced)
For granular control, use Safari Content Blocker format rules:
<ContentFilteringWebView
source={{ uri: 'https://example.com' }}
contentRules={[
// Block all third-party resources
{
trigger: {
urlFilter: '.*',
loadType: ['third-party'],
},
action: { type: 'block' },
},
// But allow specific CDN
{
trigger: {
urlFilter: '^https://cdn\\.trusted\\.com/',
},
action: { type: 'ignore-previous-rules' },
},
// Hide ad elements
{
trigger: { urlFilter: '.*' },
action: { type: 'css-display-none', selector: '.ad-banner, #sidebar-ad' },
},
// Upgrade HTTP to HTTPS
{
trigger: { urlFilter: '^http://' },
action: { type: 'make-https' },
},
]}
/>API Reference
ContentFilteringWebView
Extends all standard WebViewProps from react-native-webview.
| Prop | Type | Description |
|------|------|-------------|
| contentRules | ContentRule[] | Custom content filtering rules |
| contentFilterPreset | ContentFilterPreset | Preset configuration for common scenarios |
| contentFilteringEnabled | boolean | Enable/disable filtering (default: true if rules provided) |
| onContentRulesReady | () => void | Called when rules are compiled (iOS only) |
| onContentRulesError | (error: Error) => void | Called when rule compilation fails |
| onResourceBlocked | (url: string, resourceType?: ResourceType) => void | Called when a resource is blocked (Android only) |
ContentFilterPreset
| Property | Type | Description |
|----------|------|-------------|
| allowedDomains | string[] | Whitelist - only allow these domains |
| blockedDomains | string[] | Blacklist - block these domains |
| blockedResourceTypes | ResourceType[] | Block specific resource types |
| blockThirdParty | boolean | Block all third-party resources |
| upgradeToHttps | boolean | Upgrade HTTP to HTTPS |
ContentRule
Rules follow the Safari Content Blocker format.
interface ContentRule {
trigger: ContentRuleTrigger;
action: ContentRuleAction;
}ContentRuleTrigger
| Property | Type | Description |
|----------|------|-------------|
| urlFilter | string | Required. Regex pattern to match URLs |
| urlFilterIsCaseSensitive | boolean | Case-sensitive matching (default: false) |
| resourceType | ResourceType[] | Match specific resource types |
| loadType | LoadType[] | 'first-party' or 'third-party' |
| ifDomain | string[] | Only apply on these domains |
| unlessDomain | string[] | Don't apply on these domains |
| ifTopUrl | string[] | Only apply if top URL matches |
| unlessTopUrl | string[] | Don't apply if top URL matches |
ContentRuleAction
| Property | Type | Description |
|----------|------|-------------|
| type | ActionType | Required. Action to perform |
| selector | string | CSS selector (for css-display-none) |
Action Types:
'block'- Block the resource'block-cookies'- Block cookies but allow resource'css-display-none'- Hide matching elements (requiresselector)'ignore-previous-rules'- Whitelist (override previous blocks)'make-https'- Upgrade request to HTTPS
ResourceType
type ResourceType =
| 'document' // Main document
| 'image' // Images
| 'style-sheet' // CSS
| 'script' // JavaScript
| 'font' // Web fonts
| 'raw' // XHR, fetch
| 'svg-document'// SVG files
| 'media' // Audio/video
| 'popup'; // PopupsLoadType
type LoadType = 'first-party' | 'third-party';Validation
Validate rules before passing them to the WebView to catch errors early:
import {
validateRules,
validatePreset,
validateRule,
formatValidationErrors,
} from 'react-native-content-filtering-webview';
// Validate a preset
const presetResult = validatePreset({
allowedDomains: ['example.com'],
blockedDomains: ['invalid domain!'], // Will fail validation
});
if (!presetResult.valid) {
console.error(formatValidationErrors(presetResult.errors));
// Output: preset.blockedDomains[0]: Invalid domain format (got: "invalid domain!")
}
// Validate custom rules
const rulesResult = validateRules([
{
trigger: { urlFilter: '(unclosed' }, // Invalid regex
action: { type: 'block' },
},
]);
if (!rulesResult.valid) {
console.error(formatValidationErrors(rulesResult.errors));
// Output: rules[0].trigger.urlFilter: URL filter contains invalid regex pattern
}
// Validate individual helpers
import { isValidDomain, isValidRegex, isValidCssSelector } from 'react-native-content-filtering-webview';
isValidDomain('example.com'); // true
isValidDomain('*.example.com'); // true (wildcard)
isValidDomain('not valid!'); // false
isValidRegex('.*'); // true
isValidRegex('^https?://'); // true
isValidRegex('(unclosed'); // false
isValidCssSelector('.ad-banner'); // true
isValidCssSelector('#sidebar > div'); // true
isValidCssSelector('<div>'); // falseUtility Functions
import {
presetToRules,
rulesToJson,
shouldBlockUrl,
urlMatchesDomain,
cleanupPersistedRules,
} from 'react-native-content-filtering-webview';
// Convert a preset to ContentRule array
const rules = presetToRules({
blockedDomains: ['ads.com'],
blockThirdParty: true,
});
// Convert rules to Safari Content Blocker JSON string
const json = rulesToJson(rules);
// Check if a URL matches a domain (includes subdomains)
urlMatchesDomain('https://sub.example.com/page', 'example.com'); // true
urlMatchesDomain('https://other.com/page', 'example.com'); // false
// Check if a URL should be blocked based on preset
shouldBlockUrl(
'https://ads.com/banner.js',
'https://mysite.com',
{ blockedDomains: ['ads.com'] }
); // true
// Clean up persisted rules from previous sessions (iOS only)
// Call on app startup if needed
await cleanupPersistedRules();Platform Differences
iOS
- Uses
WKContentRuleListfor native WebKit-level filtering - Rules are compiled once and cached
- Extremely efficient - filtering happens in the WebKit process
onResourceBlockedis NOT available (WebKit limitation)- Rules persist across app sessions (use
cleanupPersistedRules()to clear)
Android
- Uses
shouldInterceptRequestfor request interception - Filtering happens in the native module
onResourceBlockedIS available- Rules are not persisted
Common Patterns
Whitelist Mode
Only allow specific domains:
<ContentFilteringWebView
source={{ uri: 'https://myapp.com' }}
contentFilterPreset={{
allowedDomains: [
'myapp.com',
'api.myapp.com',
'cdn.myapp.com',
],
}}
/>Privacy Mode
Block trackers and third-party content:
<ContentFilteringWebView
source={{ uri: 'https://example.com' }}
contentFilterPreset={{
blockThirdParty: true,
blockedDomains: [
'google-analytics.com',
'facebook.com',
'doubleclick.net',
],
upgradeToHttps: true,
}}
/>Ad Blocking with Element Hiding
<ContentFilteringWebView
source={{ uri: 'https://example.com' }}
contentRules={[
// Block ad domains
{
trigger: { urlFilter: '^https?://([a-z0-9-]+\\.)*(ads|analytics|tracking)\\.' },
action: { type: 'block' },
},
// Hide ad containers
{
trigger: { urlFilter: '.*' },
action: {
type: 'css-display-none',
selector: '.ad, .ads, .advertisement, [class*="ad-"], [id*="ad-"]',
},
},
]}
/>Combining Preset and Custom Rules
<ContentFilteringWebView
source={{ uri: 'https://example.com' }}
contentFilterPreset={{
blockThirdParty: true,
}}
contentRules={[
// Allow specific third-party CDN
{
trigger: { urlFilter: '^https://cdn\\.jsdelivr\\.net/' },
action: { type: 'ignore-previous-rules' },
},
]}
/>Error Handling
<ContentFilteringWebView
source={{ uri: 'https://example.com' }}
contentFilterPreset={{ allowedDomains: ['example.com'] }}
onContentRulesReady={() => {
console.log('Content rules compiled successfully');
}}
onContentRulesError={(error) => {
console.error('Failed to compile rules:', error.message);
}}
onResourceBlocked={(url, resourceType) => {
console.log(`Blocked ${resourceType || 'resource'}: ${url}`);
}}
/>TypeScript
Full TypeScript support with exported types:
import type {
ContentFilteringWebViewProps,
ContentFilterPreset,
ContentRule,
ContentRuleAction,
ContentRuleTrigger,
ResourceType,
LoadType,
ValidationError,
ValidationResult,
} from 'react-native-content-filtering-webview';License
MIT
