The shortkit Web SDK provides a video feed experience for browsers using hls.js and dash.js under a unified API.
Requirements
- Modern browser (Chrome 80+, Firefox 75+, Safari 14+, Edge 80+)
- For React integration: React 17 or later
Installation
npm install @shortkit/web
<script src="https://cdn.shortkit.dev/web/v1/shortkit.min.js"></script>
Initialization
Initialize the SDK before mounting any feed components:
import { shortkit } from '@shortkit/web';
shortkit.initialize({
apiKey: 'pk_live_your_publishable_key',
config: {
feedOrientation: 'vertical',
feedHeight: 'fullscreen',
controls: {
playPause: true,
scrubber: true,
playbackSpeed: {
enabled: true,
options: [1.0, 1.25, 1.5, 2.0]
},
captions: {
enabled: true,
defaultOn: false
},
volume: true,
share: { enabled: true }
},
theme: {
primaryColor: '#FF6600',
controlsTint: '#FFFFFF',
backgroundColor: '#000000'
}
},
environment: 'production'
});
With CDN, access the global shortkit object:
<script src="https://cdn.shortkit.dev/web/v1/shortkit.min.js"></script>
<script>
shortkit.initialize({
apiKey: 'pk_live_your_publishable_key',
config: {
feedOrientation: 'vertical',
feedHeight: 'fullscreen'
}
});
</script>
Displaying the feed
React
Use the ShortkitFeed component:
import React from 'react';
import { ShortkitFeed } from '@shortkit/web/react';
export function VideoFeed() {
return (
<div style={{ width: '100%', height: '100vh' }}>
<ShortkitFeed />
</div>
);
}
With filters:
import React from 'react';
import { ShortkitFeed } from '@shortkit/web/react';
export function SportsFeed() {
return (
<div style={{ width: '100%', height: '100vh' }}>
<ShortkitFeed
filter={{
tags: ['sports', 'highlights']
}}
/>
</div>
);
}
Vanilla JavaScript
Mount the feed to a container element:
import { shortkit } from '@shortkit/web';
const container = document.getElementById('video-feed');
const feed = shortkit.mountFeed(container);
// Later, to unmount:
feed.unmount();
<div id="video-feed" style="width: 100%; height: 100vh;"></div>
<script type="module">
import { shortkit } from '@shortkit/web';
shortkit.initialize({ /* config */ });
const container = document.getElementById('video-feed');
shortkit.mountFeed(container);
</script>
Partial-height feed
For feeds that don’t occupy the full viewport:
import React from 'react';
import { ShortkitFeed } from '@shortkit/web/react';
export function PartialFeed() {
return (
<div className="feed-container">
<ShortkitFeed
height={{ percentage: 0.7 }} // 70% of container
/>
</div>
);
}
.feed-container {
width: 400px;
height: 80vh;
margin: 0 auto;
}
User identity
Associate user identity for personalized feeds:
import { shortkit } from '@shortkit/web';
// When user logs in
function handleLogin(userId: string) {
shortkit.setUserId(userId);
}
// When user logs out
function handleLogout() {
shortkit.clearUserId();
}
Event callbacks
React
import React from 'react';
import { ShortkitFeed, Content, ShortkitError } from '@shortkit/web/react';
export function VideoFeed() {
const handleShare = async (content: Content) => {
if (navigator.share) {
await navigator.share({
title: content.title,
url: content.shareUrl
});
} else {
// Fallback: copy to clipboard
await navigator.clipboard.writeText(content.shareUrl);
alert('Link copied to clipboard!');
}
};
const handleAction = (action: string, content: Content) => {
switch (action) {
case 'bookmark':
// Save to bookmarks
break;
case 'readMore':
window.location.href = content.metadata?.articleUrl;
break;
}
};
const handleError = (error: ShortkitError) => {
console.error('shortkit error:', error.message);
};
return (
<div style={{ width: '100%', height: '100vh' }}>
<ShortkitFeed
onShareRequested={handleShare}
onActionTapped={handleAction}
onError={handleError}
/>
</div>
);
}
Vanilla JavaScript
import { shortkit } from '@shortkit/web';
const feed = shortkit.mountFeed(container, {
onShareRequested: (content) => {
navigator.share({
title: content.title,
url: content.shareUrl
});
},
onActionTapped: (action, content) => {
console.log('Action:', action, 'Content:', content.id);
},
onError: (error) => {
console.error('Error:', error);
},
onMetadataLoaded: (content, metadata) => {
console.log('Metadata:', metadata);
}
});
Deep linking
Handle deep links to open specific content:
import { shortkit } from '@shortkit/web';
// Check URL on page load
function handleRouteChange() {
const path = window.location.pathname;
const match = path.match(/\/watch\/(\w+)/);
if (match) {
const contentId = match[1];
shortkit.openContent(contentId);
}
}
// Initial check
handleRouteChange();
// Listen for navigation (with your router)
window.addEventListener('popstate', handleRouteChange);
With React Router:
import { useEffect } from 'react';
import { useParams } from 'react-router-dom';
import { shortkit } from '@shortkit/web';
function WatchPage() {
const { contentId } = useParams<{ contentId: string }>();
useEffect(() => {
if (contentId) {
shortkit.openContent(contentId);
}
}, [contentId]);
return <ShortkitFeed />;
}
Entry widget
Create a mini-player widget for other pages:
React
import React from 'react';
import { ShortkitEntryWidget, Content } from '@shortkit/web/react';
import { useNavigate } from 'react-router-dom';
export function HomePage() {
const navigate = useNavigate();
const handleContentSelected = (content: Content) => {
navigate(`/videos?start=${content.id}`);
};
return (
<div>
<h2>Latest Videos</h2>
<ShortkitEntryWidget
style={{ height: 200 }}
itemCount={5}
autoPlay={true}
onContentSelected={handleContentSelected}
/>
{/* Other content */}
</div>
);
}
Vanilla JavaScript
import { shortkit } from '@shortkit/web';
const widgetContainer = document.getElementById('video-widget');
shortkit.mountEntryWidget(widgetContainer, {
itemCount: 5,
autoPlay: true,
onContentSelected: (content) => {
window.location.href = `/videos?start=${content.id}`;
}
});
Responsive behavior
The feed automatically adapts to container size. For mobile-like experiences on desktop:
import React from 'react';
import { ShortkitFeed } from '@shortkit/web/react';
export function MobileFeed() {
return (
<div className="mobile-container">
<ShortkitFeed />
</div>
);
}
.mobile-container {
max-width: 430px;
height: 100vh;
margin: 0 auto;
}
@media (max-width: 430px) {
.mobile-container {
max-width: 100%;
}
}
Keyboard shortcuts
The feed supports keyboard navigation when focused:
| Key | Action |
|---|
Space | Play/Pause |
↑ / ↓ | Previous/Next video |
← / → | Seek backward/forward 5s |
M | Mute/Unmute |
F | Toggle fullscreen |
C | Toggle captions |
Disable keyboard handling if needed:
<ShortkitFeed keyboardEnabled={false} />
TypeScript types
Full TypeScript definitions are included:
import type {
ShortkitConfig,
FeedConfig,
Content,
ShortkitError,
FeedFilter,
} from '@shortkit/web';
const config: ShortkitConfig = {
apiKey: 'pk_live_...',
config: {
feedOrientation: 'vertical',
feedHeight: 'fullscreen',
},
};
Server-side rendering
The SDK is client-side only. For SSR frameworks (Next.js, Remix), use dynamic imports:
Next.js
'use client';
import dynamic from 'next/dynamic';
const ShortkitFeed = dynamic(
() => import('@shortkit/web/react').then(mod => mod.ShortkitFeed),
{ ssr: false }
);
export function VideoFeed() {
return <ShortkitFeed />;
}
Initialize in a client component:
'use client';
import { useEffect } from 'react';
import { shortkit } from '@shortkit/web';
export function ShortkitProvider({ children }) {
useEffect(() => {
shortkit.initialize({
apiKey: 'pk_live_your_publishable_key',
config: { /* ... */ }
});
}, []);
return children;
}
Content Security Policy
If using CSP headers, allow these sources:
script-src 'self' https://cdn.shortkit.dev;
connect-src 'self' https://api.shortkit.dev https://*.shortkit.dev;
media-src 'self' blob: https://*.shortkit.dev;
img-src 'self' data: https://*.shortkit.dev;
Browser support
| Browser | Minimum Version |
|---|
| Chrome | 80+ |
| Firefox | 75+ |
| Safari | 14+ |
| Edge | 80+ |
| iOS Safari | 14+ |
| Chrome Android | 80+ |
Internet Explorer is not supported.
Debugging
Enable debug mode:
shortkit.initialize({
apiKey: 'pk_live_your_publishable_key',
config: { /* ... */ },
environment: 'development'
});
// Or set log level explicitly
shortkit.setLogLevel('verbose');
View logs in the browser developer console.
Next steps