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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@bernierllc/content-type-instagram-post

v1.0.0

Published

Instagram post content type with aspect ratio validation and Graph API publishing

Downloads

119

Readme

@bernierllc/content-type-instagram-post

Instagram post content type with aspect ratio validation and Graph API publishing support.

Installation

npm install @bernierllc/content-type-instagram-post

Features

  • Instagram-Specific Validation:

    • Aspect ratio enforcement (1:1, 4:5, 1.91:1, 9:16)
    • Minimum dimensions validation (320x320)
    • Caption length limits (2,200 characters)
    • Hashtag validation (max 30 hashtags)
    • @mention parsing and validation
  • Instagram Graph API Integration:

    • Single image publishing
    • Carousel support (2-10 images)
    • Location tagging
    • Alt text for accessibility
    • Automatic retry on failures
  • Image Processing:

    • Sharp integration for aspect ratio calculation
    • Dimension validation
    • Image metadata extraction

Usage

Basic Setup

import { InstagramPostContentType } from '@bernierllc/content-type-instagram-post';

const instagram = new InstagramPostContentType({
  instagram: {
    accessToken: process.env.INSTAGRAM_ACCESS_TOKEN,
    userId: process.env.INSTAGRAM_USER_ID,
  },
  validation: {
    allowedAspectRatios: ['1:1', '4:5', '1.91:1'], // Optional: customize allowed ratios
    minWidth: 320,
    minHeight: 320,
    maxCaptionLength: 2200,
    maxHashtags: 30,
  },
});

Validate Instagram Image

const imageBuffer = await fs.readFile('photo.jpg');

const result = await instagram.validateInstagram(imageBuffer, 'image/jpeg');

if (result.valid) {
  console.log('Image is valid for Instagram!');
  console.log('Dimensions:', result.metadata);
} else {
  console.error('Validation failed:', result.error);
}

Validate Caption

const caption = 'Amazing sunset! #travel #photography @friend';

const result = instagram.validateCaption(caption);

if (result.success) {
  console.log('Caption:', result.data.caption);
  console.log('Hashtags:', result.data.hashtags); // ['travel', 'photography']
  console.log('Mentions:', result.data.mentions); // ['friend']
} else {
  console.error('Caption validation failed:', result.error);
}

Publish Single Image

const result = await instagram.publishToInstagram(
  'https://example.com/image.jpg',
  'Amazing sunset! #travel #photography',
  {
    name: 'Golden Gate Bridge',
    facebookPlaceId: 'place-123',
  },
  'A beautiful sunset over the Golden Gate Bridge'
);

if (result.success) {
  console.log('Published!', result.data.permalink);
} else {
  console.error('Publishing failed:', result.error);
}

Publish Carousel

const items = [
  {
    publicUrl: 'https://example.com/img1.jpg',
    altText: 'First image description',
  },
  {
    publicUrl: 'https://example.com/img2.jpg',
    altText: 'Second image description',
  },
  {
    publicUrl: 'https://example.com/img3.jpg',
    altText: 'Third image description',
  },
];

const result = await instagram.publishCarousel(
  items,
  'Check out these amazing photos! #travel',
  {
    name: 'Paris, France',
    facebookPlaceId: 'place-456',
  }
);

if (result.success) {
  console.log('Carousel published!', result.data.permalink);
} else {
  console.error('Publishing failed:', result.error);
}

Configuration

Instagram API Configuration

interface InstagramApiConfig {
  accessToken?: string;      // Instagram Graph API access token
  userId?: string;           // Instagram Business Account user ID
  apiVersion?: string;       // API version (default: 'v18.0')
  maxCarouselItems?: number; // Maximum carousel items (default: 10)
}

Validation Configuration

interface InstagramValidationConfig {
  allowedAspectRatios: InstagramAspectRatio[]; // Allowed ratios
  minWidth: number;                             // Minimum width (default: 320)
  minHeight: number;                            // Minimum height (default: 320)
  recommendedWidth: number;                     // Recommended width (default: 1080)
  maxCaptionLength: number;                     // Max caption length (default: 2200)
  maxHashtags: number;                          // Max hashtags (default: 30)
}

Environment Variables

# Instagram API Configuration
INSTAGRAM_ACCESS_TOKEN=your-access-token
INSTAGRAM_USER_ID=your-user-id
INSTAGRAM_API_VERSION=v18.0
INSTAGRAM_MAX_CAROUSEL_ITEMS=10

# Validation Configuration
INSTAGRAM_MIN_WIDTH=320
INSTAGRAM_MIN_HEIGHT=320
INSTAGRAM_RECOMMENDED_WIDTH=1080
INSTAGRAM_MAX_CAPTION_LENGTH=2200
INSTAGRAM_MAX_HASHTAGS=30

Instagram Requirements

Aspect Ratios

| Ratio | Type | Use Case | |-------|------|----------| | 1:1 | Square | Standard posts | | 4:5 | Portrait | Vertical photos | | 1.91:1 | Landscape | Wide photos | | 9:16 | Stories | Vertical stories |

Image Dimensions

  • Minimum: 320x320 pixels
  • Recommended: 1080x1080 pixels (square), 1080x1350 pixels (portrait)
  • Maximum file size: 8 MB (enforced by Instagram)

Caption Limits

  • Maximum length: 2,200 characters
  • Maximum hashtags: 30 hashtags
  • Mentions: Unlimited @mentions

Carousel Limits

  • Minimum items: 2 images
  • Maximum items: 10 images
  • All images must meet Instagram's aspect ratio and dimension requirements

API Reference

InstagramPostContentType

Main class for Instagram post content type management.

Methods

validateInstagram(file: Buffer, mimeType: string): Promise<ImageValidationResult>

Validates an image buffer against Instagram requirements.

validateCaption(caption: string): PackageResult<CaptionParseResult>

Validates and parses an Instagram caption.

publishToInstagram(publicUrl, caption, location?, altText?): Promise<InstagramPublishResult>

Publishes a single image to Instagram.

publishCarousel(items, caption, location?): Promise<InstagramPublishResult>

Publishes a carousel (multiple images) to Instagram.

getAllowedAspectRatios(): InstagramAspectRatio[]

Returns the list of allowed aspect ratios.

getValidationConfig(): InstagramValidationConfig

Returns the current validation configuration.

Utility Functions

Aspect Ratio

import { calculateAspectRatio, isValidAspectRatio } from '@bernierllc/content-type-instagram-post';

const ratio = calculateAspectRatio(1080, 1080); // '1:1'
const valid = isValidAspectRatio('1:1', ['1:1', '4:5']); // true

Caption Parsing

import { extractHashtags, extractMentions, parseCaption } from '@bernierllc/content-type-instagram-post';

const hashtags = extractHashtags('Amazing! #travel #photography'); // ['travel', 'photography']
const mentions = extractMentions('Thanks @friend and @photographer'); // ['friend', 'photographer']

const parsed = parseCaption('Great shot! #travel @friend');
// { caption: '...', hashtags: ['travel'], mentions: ['friend'] }

Integration Status

  • Logger: not-applicable - Core content type focused on validation
  • Docs-Suite: ready - Complete TypeDoc API documentation
  • NeverHub: not-applicable - Core package without event-driven requirements

Error Handling

All methods return structured results following the PackageResult pattern:

interface PackageResult<T = any> {
  success: boolean;
  data?: T;
  error?: string;
}

Example error handling:

const result = await instagram.publishToInstagram(url, caption);

if (!result.success) {
  if (result.error?.includes('Rate limit')) {
    console.log('Rate limited, retry later');
  } else if (result.error?.includes('Invalid access token')) {
    console.log('Refresh access token');
  } else {
    console.error('Unknown error:', result.error);
  }
}

Dependencies

  • @bernierllc/content-type-registry - Content type registration system
  • @bernierllc/content-type-image - Base image content type
  • zod - Schema validation
  • sharp - Image processing
  • axios - HTTP client for Instagram API

License

Copyright (c) 2025 Bernier LLC

This file is licensed to the client under a limited-use license. The client may use and modify this code only within the scope of the project it was delivered for. Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.

Related Packages

Support

For issues or questions, contact Bernier LLC.