Skip to main content
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

Initialization

Initialize the SDK before mounting any feed components:
main.ts
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:
VideoFeed.tsx
import React from 'react';
import { ShortkitFeed } from '@shortkit/web/react';

export function VideoFeed() {
  return (
    <div style={{ width: '100%', height: '100vh' }}>
      <ShortkitFeed />
    </div>
  );
}
With filters:
SportsFeed.tsx
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:
PartialFeed.tsx
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

VideoFeed.tsx
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:
router.ts
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:
App.tsx
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

HomePage.tsx
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:
MobileFeed.tsx
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:
KeyAction
SpacePlay/Pause
/ Previous/Next video
/ Seek backward/forward 5s
MMute/Unmute
FToggle fullscreen
CToggle 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

VideoFeed.tsx
'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:
providers.tsx
'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

BrowserMinimum Version
Chrome80+
Firefox75+
Safari14+
Edge80+
iOS Safari14+
Chrome Android80+
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