Add a stream of ads with Add-Stream.
npm install adstreamFlutter using WebView
bash
npm install adstream
or
yarn add adstream
`
---
📦 Usage
`tsx
import React from "react";
import { AdStream } from "adstream";
function App() {
return ;
}
export default App;
`
$3
`tsx
import React from "react";
import { AdStream } from "adstream";
function App() {
return (
zoneId={200}
height={{ xs: 200, md: 300, lg: 400, xl: 500 }}
width="100%"
aspectRatio="4 / 3"
boxShadow={4}
sx={{ borderRadius: 12, backgroundColor: "#fafafa" }}
loader={Loading single ad...}
errorText={Oops! Could not load the ad.}
/>
);
}
export default App;
`
---
$3
✅ Pages Router (with SSR-safe dynamic import)
Use next/dynamic to safely render AdStream client-side only:
`tsx
// components/SafeAdStreamWrapper.tsx
import React from "react";
import { AdStream } from "adstream";
const SafeAdStreamWrapper = () => {
return (
zoneId={200}
height={{ xs: 200, md: 336 }}
aspectRatio="16 / 9"
boxShadow={2}
sx={{ borderRadius: 0 }}
width="100%"
/>
);
};
export default SafeAdStreamWrapper;
// Then import it dynamically in your page:
// pages/index.tsx or any route
import dynamic from "next/dynamic";
const SafeAdStream = dynamic(
() => import("../components/SafeAdStreamWrapper"),
{
ssr: false,
loading: () => Loading ads...,
}
);
export default function HomePage() {
return (
Dashboard
);
}
`
---
✅ App Router (/app/page.tsx)
With App Router, make sure to mark the component with "use client" and import AdStream normally:
`tsx
// app/demo/page.tsx
"use client";
import { AdStream } from "adstream";
import { Stack } from "@mui/material";
export default function Demo() {
return (
zoneId={200}
aspectRatio="16 / 9"
boxShadow={3}
width="100%"
height={{ xs: 200, md: 300 }}
/>
);
}
`
---
🎛️ Customization
$3
| Prop | Type | Description | |
| ------------- | ---------------- | -------------------------------------- | ------------------------- |
| zoneId | number | The ad zone ID | |
| loader | ReactNode | Optional loader fallback | |
| height | \number | object\ | Responsive height |
| width | \number | string\ | Width of the ad component |
| aspectRatio | string | CSS aspect ratio for responsive layout | |
| boxShadow | number | MUI shadow level | |
| sx | SxProps | Additional style overrides | |
| errorText | ReactNode | Error message if ad fails to load | |
---
🌐 Using in Plain HTML via Web Components
You can use adstream in any HTML file by loading the built-in Web Component.
`html
Ad Stream Demo
zoneid="18"
aspectratio="16 / 9"
height='{"xs": 200, "md": 300}'
width="100%"
sx='{"borderRadius": 1}'
>
`
---
📱 Use with Flutter WebView
AdStream Web Components work in any mobile app that can render HTML — including Flutter apps using a WebView.
$3
`dart
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'dart:async';
import 'package:url_launcher/url_launcher.dart';
/// A highly customizable ad banner component using AdStream technology
/// Features:
/// - Responsive ad container
/// - Memory-efficient WebView management
/// - External link handling
class AdStreamBanner extends StatefulWidget {
final int? zoneId;
final int zoneWidth;
final int zoneHeight;
const AdStreamBanner({
super.key,
this.zoneId,
required this.zoneWidth,
required this.zoneHeight,
});
@override
State createState() => _AdStreamBannerState();
}
class _AdStreamBannerState extends State {
late WebViewController controller;
@override
void dispose() {
controller.clearCache();
super.dispose();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
_initializeController();
}
/// Generates the HTML content for the ad banner
getAdHtml() {
String html = '''
zoneid="${widget.zoneId}"
aspectratio="16 / 9"
height='{"xs": ${_calculateHeight()}, "md": ${_calculateHeight()}}'
width="100%"
sx='{"borderRadius": 1}'
>
''';
return html;
}
void _initializeController() {
controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(Colors.white)
..addJavaScriptChannel(
'ExternalLink',
onMessageReceived: (JavaScriptMessage message) {
_launchExternalUrl(message.message);
},
)
..setNavigationDelegate(
NavigationDelegate(
onNavigationRequest: (NavigationRequest request) {
if (request.url.startsWith("http")) {
_launchExternalUrl(request.url);
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
onPageStarted: (String url) {},
onPageFinished: (String url) {},
onWebResourceError: (WebResourceError error) {},
),
)
..loadHtmlString(getAdHtml());
}
@override
Widget build(BuildContext context) {
return SizedBox(
width: MediaQuery.of(context).size.width,
height: _calculateHeight(),
child: WebViewWidget(
controller: controller,
),
);
}
double _calculateHeight() {
final screenWidth = MediaQuery.of(context).size.width;
final aspectRatio = widget.zoneWidth / widget.zoneHeight;
double calculatedHeight = screenWidth / aspectRatio;
return calculatedHeight.clamp(50.0, 300.0);
}
Future _launchExternalUrl(String url) async {
final uri = Uri.tryParse(url);
if (uri != null && await canLaunchUrl(uri)) {
await launchUrl(uri, mode: LaunchMode.externalApplication);
} else {
debugPrint("❌ Could not launch $url");
}
}
}
``