Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

comic-vine-sdk

AllyMurray74MIT1.3.2TypeScript support: included

A JS/TS client for the Comic Vine API

comic, comic-metadata, comic-vine, comic-vine-api, comic-vine-client, comic-vine-javascript, comic-vine-js, comic-vine-node, comic-vine-nodejs, comic-vine-sdk, comic-vine-ts, comic-vine-typescript, comics, metadata

readme

Comic Vine SDK

NPM Version License Node.js Version TypeScript

The Comic Vine SDK provides convenient access to the Comic Vine API from applications written in JavaScript/TypeScript. The API provides full access to the structured-wiki content.

Table of Contents

Requirements

  • Node.js 20.0.0 or higher
  • npm, yarn, or pnpm

Installation

Choose your preferred package manager:

pnpm

pnpm add comic-vine-sdk

npm

npm install comic-vine-sdk

yarn

yarn add comic-vine-sdk

Quick Start

import ComicVine from 'comic-vine-sdk';

// Initialize the client
const comicVine = new ComicVine('your-api-key-here');

// Fetch a single publisher
const publisher = await comicVine.publisher.retrieve(1859);
console.log(publisher.name);

// Fetch a list of issues
const issues = await comicVine.issue.list({ limit: 10 });
console.log(issues.data.map((issue) => issue.name));

// Fetch with field limiting
const limitedIssue = await comicVine.issue.retrieve(1234, {
  fieldList: ['id', 'name', 'description'],
});
console.log(limitedIssue.name);

API Key Security

⚠️ Important: Never expose your API key in client-side code or commit it to version control.

Create a .env file:

# .env file
COMIC_VINE_API_KEY=your-api-key-here

Use in your application:

import ComicVine from 'comic-vine-sdk';

const comicVine = new ComicVine(process.env.COMIC_VINE_API_KEY);

Browser Usage

The Comic Vine API doesn't support CORS. For browser usage, you'll need:

  • A backend proxy to make API calls
  • Server-side API key storage (never send keys to the browser)

Example proxy setup:

// Backend API route (Express.js example)
app.get('/api/comic-vine/publisher/:id', async (req, res) => {
  try {
    const comicVine = new ComicVine(process.env.COMIC_VINE_API_KEY);
    const publisher = await comicVine.publisher.retrieve(req.params.id);
    res.json(publisher);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

TypeScript Typings

There's a good chance you may find an issue with the typings in the API response objects. They were generated using sample data from the API, if you find a problem open an issue detailing the problem along with the request details so I can add that request to the sample dataset. While you wait for it to be fixed add // @ts-expect-error above the line causing the problem. This will allow you to compile in the meantime but will flag when the problem has been fixed.

Rate Limiting

The Comic Vine API implements rate limiting to ensure fair usage and API health for all users.

⚠️ Note: This library will soon include built-in solutions for caching, request deduplication, and rate limiting. The examples below are temporary workarounds until these features are available.

Limits

  • 200 requests per resource per hour - Official limit per user
  • Velocity detection - Prevents too many requests per second
  • Temporary blocks - May occur if limits are exceeded

Best Practices

Cache responses to avoid duplicate requests:

// Example: Simple in-memory cache
const cache = new Map();

async function getCachedPublisher(id) {
  const cacheKey = `publisher-${id}`;

  if (cache.has(cacheKey)) {
    return cache.get(cacheKey);
  }

  const publisher = await comicVine.publisher.retrieve(id);
  cache.set(cacheKey, publisher);

  return publisher;
}

Implement delays between requests:

// Example: Add delay between requests
async function fetchMultipleIssues(ids) {
  const issues = [];

  for (const id of ids) {
    const issue = await comicVine.issue.retrieve(id);
    issues.push(issue);

    // Wait 100ms between requests
    await new Promise((resolve) => setTimeout(resolve, 100));
  }

  return issues;
}

Use pagination wisely:

// Instead of making many small requests
const issues = await comicVine.issue.list({ limit: 100 }); // Better
// Rather than
const issues = await comicVine.issue.list({ limit: 10 }); // Less efficient

Error Handling

The Comic Vine SDK provides specific error types to help you handle different failure scenarios gracefully.

Error Types

All errors extend the base BaseError class and include:

  • message: Human-readable error description
  • help: Guidance on how to resolve the issue

Common Error Types:

Error Type When It Occurs How to Handle
ComicVineUnauthorizedError Invalid API key Check your API key
ComicVineObjectNotFoundError Resource doesn't exist Verify the resource ID
OptionsValidationError Invalid request options Check your parameters
ComicVineGenericRequestError API request failed Retry or check API status
ComicVineSubscriberOnlyError Premium content access Requires Comic Vine subscription

Basic Error Handling

Simple try-catch:

import ComicVine from 'comic-vine-sdk';

const comicVine = new ComicVine('your-api-key-here');

try {
  const publisher = await comicVine.publisher.retrieve(999999);
  console.log(publisher.name);
} catch (error) {
  console.error('Error:', error.message);
  console.error('Help:', error.help);
}

Specific Error Handling

Handle different error types:

import ComicVine, {
  ComicVineUnauthorizedError,
  ComicVineObjectNotFoundError,
  OptionsValidationError,
} from 'comic-vine-sdk';

const comicVine = new ComicVine('your-api-key-here');

try {
  const issue = await comicVine.issue.retrieve(999999);
} catch (error) {
  if (error instanceof ComicVineUnauthorizedError) {
    console.error(
      'Invalid API key. Get one from: https://comicvine.gamespot.com/api/',
    );
  } else if (error instanceof ComicVineObjectNotFoundError) {
    console.error('Issue not found. Please check the ID.');
  } else if (error instanceof OptionsValidationError) {
    console.error('Invalid request parameters:', error.message);
  } else {
    console.error('Unexpected error:', error.message);
  }
}

Robust Error Handling with Retry

Implement retry logic for transient errors:

async function fetchWithRetry(fetchFn, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await fetchFn();
    } catch (error) {
      // Don't retry on client errors
      if (
        error instanceof ComicVineUnauthorizedError ||
        error instanceof ComicVineObjectNotFoundError ||
        error instanceof OptionsValidationError
      ) {
        throw error;
      }

      // Retry on server errors
      if (attempt === maxRetries) {
        throw error;
      }

      // Wait before retrying (exponential backoff)
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise((resolve) => setTimeout(resolve, delay));
    }
  }
}

// Usage
try {
  const publisher = await fetchWithRetry(() =>
    comicVine.publisher.retrieve(1859),
  );
  console.log(publisher.name);
} catch (error) {
  console.error('Failed after retries:', error.message);
}

Error Handling in Lists

Handle errors when processing multiple items:

async function fetchMultipleIssues(ids) {
  const results = [];
  const errors = [];

  for (const id of ids) {
    try {
      const issue = await comicVine.issue.retrieve(id);
      results.push({ id, issue });
    } catch (error) {
      errors.push({ id, error: error.message });
    }
  }

  return { results, errors };
}

// Usage
const { results, errors } = await fetchMultipleIssues([1, 2, 999999]);
console.log(`Successfully fetched: ${results.length}`);
console.log(`Errors: ${errors.length}`);

Advanced Usage

Available Filters

Common filter options for list methods:

Filter by name:

const issues = await comicVine.issue.list({
  filter: { name: 'The Boys' },
});

Filter by date range:

const recentIssues = await comicVine.issue.list({
  filter: {
    date_added: '2024-01-01 00:00:00|2024-12-31 23:59:59',
  },
});

Multiple filters:

const filteredIssues = await comicVine.issue.list({
  filter: {
    name: 'Spider-Man',
    date_added: '2024-01-01 00:00:00|2024-12-31 23:59:59',
  },
});

Publisher-specific content:

const marvelIssues = await comicVine.issue.list({
  filter: {
    publisher: 'Marvel Comics',
  },
  limit: 50,
});

Common Field Lists

Minimal issue data:

const lightIssue = await comicVine.issue.retrieve(1234, {
  fieldList: ['id', 'name', 'issue_number'],
});

Full issue details:

const fullIssue = await comicVine.issue.retrieve(1234, {
  fieldList: ['id', 'name', 'description', 'cover_date', 'image', 'volume'],
});

Character essentials:

const character = await comicVine.character.retrieve(1234, {
  fieldList: ['id', 'name', 'description', 'image', 'publisher', 'powers'],
});

Publisher overview:

const publisher = await comicVine.publisher.retrieve(1234, {
  fieldList: [
    'id',
    'name',
    'description',
    'image',
    'date_added',
    'location_city',
  ],
});

Sorting and Ordering

Sort by date (newest first):

const recentIssues = await comicVine.issue.list({
  sort: 'date_added:desc',
  limit: 10,
});

Sort by name:

const sortedCharacters = await comicVine.character.list({
  sort: 'name:asc',
  limit: 100,
});

Complex Queries

Combine multiple options:

const complexQuery = await comicVine.issue.list({
  filter: {
    name: 'Spider-Man',
    date_added: '2024-01-01 00:00:00|2024-12-31 23:59:59',
  },
  fieldList: ['id', 'name', 'issue_number', 'cover_date', 'image'],
  sort: 'cover_date:desc',
  limit: 25,
  offset: 0,
});

Roadmap

  • Expandable responses

  • Cached responses

  • Rate limiting

Comic Vine Resources

Comic Vine resources list

The library exposes an object for each Comic Vine resource, the object names are singular and expose a retrieve method that maps to the singular resource and a list method that maps to the plural resource.

The following table lists the resources that have been implemented and how the retrieve and list methods map to the API. Most resources are a direct mapping but object has been mapped to thing, this is due to object being a reserved word in JS and thing matches the Comic Vine wiki.

Library resource object Retrieve Method API Resource List Method API Resource
character character characters
concept concept concepts
episode episode episodes
issue issue issues
location location locations
movie movie movies
origin origin origins
person person people
power power powers
promo promo promos
publisher publisher publishers
series series series_list
storyArc story_arc story_arcs
team team teams
thing object objects
video video videos
videoCategory video_category video_categories
videoType video_type video_types
volume volume volumes

Usage/Examples

Initialization

The package needs to be configured with your API key, Grab an API key. Require it with the key's value:

const ComicVine = require('comic-vine-sdk');
const comicVine = new ComicVine('your-api-key-here');

comicVine.publisher
  .retrieve(1859)
  .then((publisher) => console.log(publisher.id))
  .catch((error) => console.error(error));

Or using ES modules and async/await:

import ComicVine from 'comic-vine-sdk';
const comicVine = new ComicVine('your-api-key-here');

(async () => {
  try {
    const publisher = await comicVine.publisher.retrieve(1859);
    console.log(publisher.name);
  } catch (error) {
    console.error(error);
  }
})();

Options

The second parameter of the constructor accepts options to configure the library

new ComicVine('your-api-key-here', options);

baseUrl

Type: string | undefined

Default: https://comicvine.gamespot.com/api/

If using this package in node this should not need set, the default value will work.

If using the package in a web browser then The Comic Vine API does not allow cross-origin requests. This option could be used to proxy the request assuming you have some safe way for the web client to fetch your api key, you don't want to send the api key to the browser in your JS bundle.

import ComicVine from 'comic-vine-sdk';

// This is just an example, to try it out you would
// have to visit (https://cors-anywhere.herokuapp.com)
// to request temporary access.
const comicVine = new ComicVine('your-api-key-here', {
  baseUrl: 'https://cors-anywhere.herokuapp.com/https://www.comicvine.com/api/',
});

(async () => {
  try {
    const publisher = await comicVine.publisher.retrieve(1859);
    console.log(publisher.name);
  } catch (error) {
    console.error(error);
  }
})();

Fetch a single resource

All resources have a retrieve method, the following example retrieves a publisher

import ComicVine from 'comic-vine-sdk';
const comicVine = new ComicVine('your-api-key-here');

(async () => {
  try {
    const publisher = await comicVine.publisher.retrieve(1859);
    console.log(publisher.name);
  } catch (error) {
    console.error(error);
  }
})();

Fetch a resource list

All resources have a list method, the following example retrieves a list of publishers

import ComicVine from 'comic-vine-sdk';
const comicVine = new ComicVine('your-api-key-here');

(async () => {
  try {
    const publishers = await comicVine.publisher.list();
    console.log(publishers.data);
  } catch (error) {
    console.error(error);
  }
})();

Limit the fields in the response payload

When making a request it's likely that only certain properties are required. Both the retrieve and list methods accept options as the second parameter. This can be used to specify the field list.

When using TypeScript this is type safe, the return type is narrowed to the field list so that intellisense only displays the properties available in the response.

import ComicVine from 'comic-vine-sdk';
const comicVine = new ComicVine('your-api-key-here');

(async () => {
  try {
    const issue = await comicVine.issue.retrieve(1234, {
      fieldList: ['id', 'name', 'description'],
    });

    // The id property is in the fieldList and will be available
    console.log(issue.id);

    // In JS dateAdded will be undefined at runtime
    // in TS the compiler will produce an error because it wasn't in the fieldList
    console.log(issue.dateAdded);

    // An object containing the id, name and description properties
    console.log(issue);
  } catch (error) {
    console.error(error);
  }
})();

Pagination

The Comic Vine API provides offset based pagination, this is done by providing a limit and offset in the request. The limit is the number of items to be returned in one page and the offset is the number of items to skip.

To fetch a page with 50 results and then move to the next page:

import ComicVine from 'comic-vine-sdk';
const comicVine = new ComicVine('your-api-key-here');

(async () => {
  try {
    const limit = 50;
    const filter = { name: 'The Boys' };

    // Retrieve the first 50 issues of The Boys (Page 1)
    const issuesPage1 = await comicVine.issue.list({ limit, filter });
    console.log(`Total issues: ${issuesPage1.data.length}`);
    console.log(issuesPage1.data.map((issue) => issue.name).join(', '));

    // Retrieve the next 50 issues of The Boys (Page 2)
    const issuesPage2 = await comicVine.issue.list({
      limit,
      filter,
      offset: 50,
    });
    console.log(`Total issues: ${issuesPage2.data.length}`);
    console.log(issuesPage2.data.map((issue) => issue.name).join(', '));
  } catch (error) {
    console.error(error);
  }
})();

Auto Pagination

This feature allows calling any list method on a resource with for await...of rather than having to track the offset for making subsequent requests.

It will make the first request and return an item from that response on each iteration, when there are no more items to return it will automatically fetch the next page from the API. This will continue until all pages have been retrieved.

import ComicVine from 'comic-vine-sdk';
const comicVine = new ComicVine('your-api-key-here');

(async () => {
  try {
    const listOptions = {
      filter: { name: 'The Boys' },
      limit: 50,
    };

    let issueNames = [];
    for await (const issue of comicVine.issue.list(listOptions)) {
      issueNames.push(issue.name);
    }

    console.log(`Total issues: ${issueNames.length}`);
    console.log(issueNames);
  } catch (error) {
    console.error(error);
  }
})();

Run Locally

Clone the project

  git clone https://github.com/AllyMurray/comic-vine.git

Go to the project directory

  cd comic-vine

Install dependencies

  npm install

Run the tests

  npm run test

Authors

changelog

Changelog

All notable changes to this project will be documented in this file. See standard-version for commit guidelines.

1.3.2 (2025-07-03)

[1.2.8] - 2024-01-01

Changed

  • Migrated from Projen to standard npm project structure
  • Updated GitHub Actions workflows to use artifact actions v4
  • Improved build process and release workflow

1.2.5 (2023-03-18)

Bug Fixes

  • upgrade zod from 3.20.2 to 3.20.5 (31755e7)
  • upgrade zod from 3.20.5 to 3.20.6 (4c32d5b)

1.2.4 (2023-01-31)

Bug Fixes

  • :package: publish typings to npm (f132dd6)

1.2.3 (2023-01-22)

Bug Fixes

  • upgrade zod from 3.19.1 to 3.20.2 (4576f78)

1.2.2 (2022-12-04)

Bug Fixes

  • typo in pagination example: typo in pagination example (3b3d3c5)

1.2.1 (2022-12-04)

Bug Fixes

  • auto pagination example: fixes the autopagination example so limit is set to 50 (a198408)

1.2.0 (2022-12-04)

Features

  • auto pagination: add auto pagination to list methods (a5fa379)

1.1.1 (2022-10-15)

Bug Fixes

  • options docs: add missing documentation for setting baseUrl (6954695)

1.1.0 (2022-10-15)

Features

  • library options: allow setting baseUrl when initializing the library (07fe7e3)

1.0.4 (2022-10-08)

Bug Fixes

  • typings: improve the api response typings (e5bf556)

1.0.3 (2022-10-07)

Bug Fixes

  • tsconfig.json: remove comments so that the file can be parsed by snyk (fe715f7)

1.0.2 (2022-10-07)

Bug Fixes

  • character details typings: birth can be null or string, change any arrays to SiteResource array (5a69bd3)

1.0.1 (2022-10-05)

Bug Fixes

  • ts build: update typescript typings to remove false positives in vscode problems window (ece4080)

1.0.0 (2022-09-30)

Bug Fixes

  • npm publish: rename npm package (37eb3a1)
  • npm publish: rename npm package to comic-vine-sdk (26fe0d8)

Features

  • gh workflow: automate release to npm (efa0a07)