npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

audio-tracker

v2.0.0

Published

A headless JavaScript library that gives you full control over web audio — playback, tracking, and Media Session integration made simple.

Readme

🎵 audio-tracker

A headless JavaScript library that gives you full control over web audio — playback, tracking, and Media Session integration made simple.

npm version npm downloads License: MIT TypeScript

🎮 Live Demo | 📖 Documentation | 💾 Installation


📋 Table of Contents


✨ Features

  • 🎯 TypeScript First - Full type definitions included, no @types needed
  • 🎵 Complete Audio Control - Play, pause, seek, volume, speed control
  • 🔄 Media Session API - Native lock screen and media key controls
  • 📱 Cross-Platform - Works on desktop and mobile browsers
  • 🎨 Framework Agnostic - Use with React, Vue, Angular, or vanilla JS
  • Flexible Input - Accept URL strings or existing HTMLAudioElement
  • 🪝 Rich Event System - 18+ callbacks for all audio events
  • 🎮 Zero Dependencies - Pure TypeScript, no external dependencies
  • 📦 Lightweight - Minimal footprint, tree-shakeable
  • 🎧 Headless - No UI, just audio control logic
  • 🧩 Modular Architecture - Extend with Media Session and Timestamp modules

📦 Installation

npm

npm install audio-tracker

yarn

yarn add audio-tracker

pnpm

pnpm add audio-tracker

CDN

<script src="https://unpkg.com/[email protected]/dist/index.js"></script>

🚀 Quick Start

import AudioTracker, { mediaSessionModule } from "audio-tracker";

// Create tracker with audio URL and options
const tracker = new AudioTracker("/path/to/audio.mp3", {
  preload: "metadata",
  loop: false,
  muted: false,
  autoplay: false,
  volume: 80,
});

// Optional: Add lock screen controls with one line
tracker.use(mediaSessionModule);

// Initialize with callbacks
tracker.init({
  onPlay: () => console.log("▶️ Playing"),
  onPause: () => console.log("⏸️ Paused"),
  onTimeUpdate: (time) => console.log(`⏱️ ${time}s`),
  onDurationChange: (duration) => console.log(`📏 Duration: ${duration}s`),
});

// Control playback
tracker.play();
tracker.pause();
tracker.seekTo(30); // Seek to 30 seconds
tracker.setVolume(80); // 80% volume
tracker.setPlaybackRate(1.5); // 1.5x speed

📚 API Documentation

Constructor

new AudioTracker(
  audioSource: string | HTMLAudioElement,
  options?: AudioTrackerOptions
)

Parameters

| Parameter | Type | Description | | ------------- | ---------------------------- | ---------------------------------------- | | audioSource | string \| HTMLAudioElement | Audio file URL or existing audio element | | options | AudioTrackerOptions | Configuration options (optional) |

Options Interface

interface AudioTrackerOptions {
  preload?: "none" | "metadata" | "auto";
  loop?: boolean;
  muted?: boolean;
  autoplay?: boolean;
  crossOrigin?: "anonymous" | "use-credentials" | null;
  volume?: number; // 0-100
}

Methods

All methods available on the AudioTracker instance.

| Method | Parameters | Returns | Description | | ----------------------- | --------------------------------------- | ------------------ | ---------------------------------------- | | Initialization | | init | callbacks: AudioCallbacks | AudioTracker | Initialize tracker with event callbacks | | use | module: AudioModule | AudioTracker | Extend functionality with a module | | Playback Controls | | play | none | Promise<void> | Start audio playback | | pause | none | void | Pause audio playback | | togglePlay | none | Promise<void> | Toggle between play and pause states | | seekTo | time: number | void | Seek to specific time in seconds | | forward | seconds?: number | void | Skip forward (default: 10 seconds) | | backward | seconds?: number | void | Skip backward (default: 10 seconds) | | isPlaying | none | boolean | Check if audio is currently playing | | Volume Controls | | setVolume | value: number | void | Set volume level (0-100) | | getVolume | none | number | Get current volume (0-100) | | toggleMute | none | boolean | Toggle mute state, returns new state | | setMuted | muted: boolean | void | Set mute state directly | | isMuted | none | boolean | Check if audio is muted | | Playback Speed | | setPlaybackRate | rate: number | void | Set playback speed (0.25 - 4.0) | | getPlaybackRate | none | number | Get current playback speed | | Audio Attributes | | setLoop | loop: boolean | void | Enable or disable looping | | isLooping | none | boolean | Check if looping is enabled | | setAutoplay | autoplay: boolean | void | Set autoplay attribute | | getAutoplay | none | boolean | Get autoplay state | | setCrossOrigin | crossOrigin: string \| null | void | Set CORS settings | | getCrossOrigin | none | string \| null | Get CORS setting | | setPreload | preload: string | void | Set preload strategy | | getPreload | none | string | Get preload strategy | | State & Information | | getDuration | none | number | Get total audio duration in seconds | | getCurrentTime | none | number | Get current playback position in seconds | | getTimeRemaining | none | number | Get remaining time in seconds | | getReadyState | none | number | Get ready state (0-4) | | getNetworkState | none | number | Get network state (0-3) | | Utilities | | formatTime | seconds: number | string | Format seconds to MM:SS format | | getAudioElement | none | HTMLAudioElement | Get underlying audio element | | subscribe | eventName: string, callback: Function | void | Subscribe to DOM events | | unsubscribe | eventName: string, callback: Function | void | Unsubscribe from DOM events | | destroy | none | void | Clean up and remove all listeners |

Method Examples

// Initialization
tracker.init({ onPlay: () => console.log("Playing") });
tracker.use(mediaSessionModule);

// Playback Controls
await tracker.play();
tracker.pause();
await tracker.togglePlay();
tracker.seekTo(45);
tracker.forward(30);
tracker.backward(15);
const playing = tracker.isPlaying();

// Volume Controls
tracker.setVolume(75);
const volume = tracker.getVolume();
const muted = tracker.toggleMute();
tracker.setMuted(true);
const isMuted = tracker.isMuted();

// Playback Speed
tracker.setPlaybackRate(1.5);
const rate = tracker.getPlaybackRate();

// Audio Attributes
tracker.setLoop(true);
const looping = tracker.isLooping();
tracker.setAutoplay(false);
const autoplay = tracker.getAutoplay();
tracker.setCrossOrigin("anonymous");
const cors = tracker.getCrossOrigin();
tracker.setPreload("metadata");
const preload = tracker.getPreload();

// State & Information
const duration = tracker.getDuration();
const currentTime = tracker.getCurrentTime();
const remaining = tracker.getTimeRemaining();
const readyState = tracker.getReadyState();
const networkState = tracker.getNetworkState();

// Utilities
const formatted = tracker.formatTime(125); // "2:05"
const audioEl = tracker.getAudioElement();
tracker.subscribe("play", () => console.log("Playing"));
tracker.unsubscribe("play", handler);
tracker.destroy();

Callbacks

All callbacks are optional. Choose which events to listen to.

interface AudioCallbacks {
  // Playback events
  onPlay?: () => void;
  onPause?: () => void;
  onEnded?: () => void;
  onPlaying?: () => void;

  // Time events
  onTimeUpdate?: (currentTime: number) => void;
  onDurationChange?: (duration: number) => void;
  onSeeking?: (time: number) => void;

  // Loading events
  onBufferChange?: (bufferedTime: number) => void;
  onBufferPercentageChange?: (percentage: number) => void;
  onWaiting?: () => void;
  onCanPlay?: () => void;
  onLoadStart?: () => void;
  onStalled?: () => void;

  // Control events
  onRateChange?: (rate: number) => void;
  onVolumeChange?: (volume: number) => void;
  onMuteChange?: (muted: boolean) => void;

  // Error handling
  onError?: (error: MediaError | null) => void;
}

Callback Reference

| Callback | Parameters | Description | | -------------------------- | --------------------------- | ------------------------------------------------- | | onPlay | none | Fires when audio starts playing | | onPause | none | Fires when audio pauses | | onEnded | none | Fires when audio playback ends | | onPlaying | none | Fires when playback resumes after buffering | | onTimeUpdate | currentTime: number | Fires continuously during playback (~4 times/sec) | | onDurationChange | duration: number | Fires when audio duration becomes available | | onSeeking | time: number | Fires when seeking starts | | onBufferChange | bufferedTime: number | Fires when buffer progress changes (in seconds) | | onBufferPercentageChange | percentage: number | Fires when buffer progress changes (0-100%) | | onWaiting | none | Fires when playback stops due to buffering | | onCanPlay | none | Fires when enough data is loaded to play | | onLoadStart | none | Fires when browser starts loading audio | | onStalled | none | Fires when network stalls | | onRateChange | rate: number | Fires when playback speed changes | | onVolumeChange | volume: number | Fires when volume changes (0-100) | | onMuteChange | muted: boolean | Fires when mute state changes | | onError | error: MediaError \| null | Fires when an error occurs |


🧩 Modules

AudioTracker supports optional modules to extend functionality.

Media Session Module

Integrates with browser's Media Session API for lock screen controls, media keys, and notification center integration.

import AudioTracker, { mediaSessionModule } from "audio-tracker";

const tracker = new AudioTracker("/audio.mp3");
tracker.use(mediaSessionModule);

// Update metadata dynamically
tracker.updateMediaSessionMetadata?.({
  title: "New Song",
  artist: "Artist Name",
  artwork: [{ src: "/cover.jpg", sizes: "512x512", type: "image/jpeg" }],
});

View Media Session API Documentation →

Timestamp Module

Track audio segments, subsegments, and speakers in real-time. Perfect for podcasts, interviews, and chaptered content.

import AudioTracker, { timestampModule } from "audio-tracker";

const tracker = new AudioTracker("/podcast.mp3", {
  timestamp: {
    segments: [
      {
        id: "intro",
        label: "intro"
        start: 0,
        end: 30,
        order: 1,
        speaker: { id: "host", name: "Host Name" },
        text: "Introduction",
      },
    ],
    gapBehavior: "persist-previous",
  },
});

tracker.use(timestampModule);

tracker.init({
  onSegmentChange: (segment) => console.log("Segment:", segment),
  onSpeakerChange: (speaker) => console.log("Speaker:", speaker),
});

// Seek to segment by ID
tracker.seekToSegmentById?.("intro");

View Timestamp API Documentation →


💡 Usage Examples

Basic Usage

import AudioTracker from "audio-tracker";

const tracker = new AudioTracker("/music.mp3");

tracker.init({
  onDurationChange: (duration) => {
    console.log(`Total duration: ${duration} seconds`);
  },
  onTimeUpdate: (currentTime) => {
    console.log(`Current time: ${currentTime} seconds`);
  },
});

tracker.play();

React Integration

import React, { useEffect, useRef, useState } from "react";
import AudioTracker from "audio-tracker";

function AudioPlayer({ audioUrl }: { audioUrl: string }) {
  const trackerRef = useRef<AudioTracker | null>(null);
  const [isPlaying, setIsPlaying] = useState(false);
  const [currentTime, setCurrentTime] = useState(0);
  const [duration, setDuration] = useState(0);
  const [volume, setVolume] = useState(100);

  useEffect(() => {
    trackerRef.current = new AudioTracker(audioUrl, {
      preload: "metadata",
      volume: 100,
    });

    trackerRef.current.init({
      onPlay: () => setIsPlaying(true),
      onPause: () => setIsPlaying(false),
      onTimeUpdate: (time) => setCurrentTime(time),
      onDurationChange: (dur) => setDuration(dur),
      onVolumeChange: (vol) => setVolume(vol),
    });

    return () => trackerRef.current?.destroy();
  }, [audioUrl]);

  const handlePlayPause = async () => {
    await trackerRef.current?.togglePlay();
  };

  const handleSeek = (e: React.ChangeEvent<HTMLInputElement>) => {
    const time = parseFloat(e.target.value);
    trackerRef.current?.seekTo(time);
  };

  return (
    <div>
      <button onClick={handlePlayPause}>
        {isPlaying ? "⏸️ Pause" : "▶️ Play"}
      </button>

      <div>
        {trackerRef.current?.formatTime(currentTime)} /
        {trackerRef.current?.formatTime(duration)}
      </div>

      <input
        type="range"
        min={0}
        max={duration}
        value={currentTime}
        onChange={handleSeek}
        step={0.1}
      />
    </div>
  );
}

export default AudioPlayer;

Vue Integration

<template>
  <div class="audio-player">
    <button @click="togglePlayPause">
      {{ isPlaying ? "⏸️ Pause" : "▶️ Play" }}
    </button>

    <div>{{ formatTime(currentTime) }} / {{ formatTime(duration) }}</div>

    <input
      type="range"
      :min="0"
      :max="duration"
      v-model="currentTime"
      @input="handleSeek"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";
import AudioTracker from "audio-tracker";

const props = defineProps<{ audioUrl: string }>();

let tracker: AudioTracker | null = null;
const isPlaying = ref(false);
const currentTime = ref(0);
const duration = ref(0);

onMounted(() => {
  tracker = new AudioTracker(props.audioUrl, { preload: "metadata" });

  tracker.init({
    onPlay: () => (isPlaying.value = true),
    onPause: () => (isPlaying.value = false),
    onTimeUpdate: (time) => (currentTime.value = time),
    onDurationChange: (dur) => (duration.value = dur),
  });
});

onUnmounted(() => tracker?.destroy());

const togglePlayPause = async () => {
  await tracker?.togglePlay();
};

const handleSeek = (e: Event) => {
  const time = parseFloat((e.target as HTMLInputElement).value);
  tracker?.seekTo(time);
};

const formatTime = (seconds: number) => {
  return tracker?.formatTime(seconds) || "0:00";
};
</script>

Using Existing Audio Element

const audioElement = document.getElementById("myAudio") as HTMLAudioElement;

const tracker = new AudioTracker(audioElement);

tracker.init({
  onPlay: () => console.log("Playing from existing element"),
});

🌐 Browser Support

Core Audio Features

Full Support - All playback, volume, and speed controls

| Browser | Minimum Version | | --------------- | --------------- | | Chrome | 57+ | | Firefox | 52+ | | Safari | 11+ | | Edge | 79+ | | Opera | 44+ | | iOS Safari | 11+ | | Android Browser | 67+ |

Media Session API

⚠️ Progressive Enhancement - Gracefully degrades on older browsers

| Browser | Media Session Support | | --------------- | --------------------- | | Chrome | ✅ 73+ | | Firefox | ✅ 82+ | | Safari | ⚠️ 15+ (partial) | | Edge | ✅ 79+ | | Opera | ✅ 60+ | | iOS Safari | ⚠️ 15+ (partial) | | Android Browser | ✅ 73+ |


🐛 Common Issues

Issue: Audio doesn't play on mobile

Solution: Mobile browsers require user interaction before playing audio.

// ❌ Won't work on mobile without user interaction
tracker.play();

// ✅ Works - triggered by user click
button.addEventListener("click", () => {
  tracker.play();
});

Issue: TypeScript errors

Solution: Make sure you're using TypeScript 4.0+

npm install typescript@latest

🤝 Contributing

Contributions are welcome! Please follow these steps:

Development Setup

# Clone the repository
git clone [email protected]:tvicky7x/audio-tracker.git
cd audio-tracker

# Install dependencies
npm install

# Build the project
npm run build

Guidelines

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Make your changes
  4. Build and test: npm run build
  5. Commit your changes: git commit -m 'Add amazing feature'
  6. Push to the branch: git push origin feature/amazing-feature
  7. Open a Pull Request

📝 Repository


📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

Copyright (c) 2025 T Vicky


💖 Support

If you find this package helpful, please consider:

  • ⭐ Starring the repository on GitHub
  • 🐛 Reporting bugs and issues
  • 💡 Suggesting new features
  • 📖 Improving documentation
  • 🔀 Contributing code

Made with ❤️ by T Vicky

Repository: github.com/tvicky7x/audio-tracker