@bernierllc/social-media-content-type-instagram
v1.2.0
Published
Instagram-specific content type definition and validation
Readme
@bernierllc/social-media-content-type-instagram
Instagram-specific content type definition and validation for the BernierLLC Content Management Suite.
Features
- Complete Instagram Content Types - Feed posts, Stories, Reels, and Carousels
- Platform Validation - Enforce Instagram's constraints (2200 char captions, 30 hashtag limit, etc.)
- Content Transformation - Convert generic social content and blog posts to Instagram format
- Fluent Builder API - Easy content creation with method chaining
- Aspect Ratio Optimization - Automatic media resizing for Instagram's 5 supported ratios
- Story & Reel Converters - Transform content into ephemeral and short-form video formats
- Hashtag Optimization - Intelligent hashtag management following Instagram best practices
- TypeScript Support - Full type safety with comprehensive interfaces
Installation
npm install @bernierllc/social-media-content-type-instagramUsage
The package provides three main classes for working with Instagram content:
- InstagramContentBuilder - Fluent API for building Instagram posts
- InstagramContentValidator - Validate content against Instagram's rules
- InstagramContentTransformer - Convert content from other formats
Quick Start
import { InstagramContentBuilder } from '@bernierllc/social-media-content-type-instagram';
const builder = new InstagramContentBuilder();
const post = builder
.setCaption('Beautiful sunset at the beach! 🌅')
.addMedia({
type: 'image',
url: 'https://example.com/sunset.jpg',
aspectRatio: 'square'
})
.addHashtags(['photography', 'sunset', 'nature'])
.setLocation({ name: 'California Beach' })
.build();
console.log(post);
// {
// caption: 'Beautiful sunset at the beach! 🌅\n\n#photography #sunset #nature',
// media: [{ type: 'image', url: '...', aspectRatio: 'square' }],
// postType: 'feed',
// location: { name: 'California Beach' }
// }Core API
Content Validation
import { InstagramContentValidator, INSTAGRAM_CONSTRAINTS } from '@bernierllc/social-media-content-type-instagram';
const validator = new InstagramContentValidator();
// Validate complete content
const result = validator.validate(content);
console.log(result.valid); // true/false
console.log(result.errors); // Array of validation errors
console.log(result.warnings); // Array of warnings
console.log(result.suggestions); // Array of optimization suggestions
// Check specific validations
validator.validateCaption('My caption'); // boolean
validator.validateMedia(mediaArray); // boolean
validator.validateHashtags(hashtagArray); // boolean
validator.validateStory(storyContent); // InstagramValidationResult
validator.validateReel(reelContent); // InstagramValidationResultContent Transformation
import { InstagramContentTransformer } from '@bernierllc/social-media-content-type-instagram';
const transformer = new InstagramContentTransformer();
// From generic social content
const instagramPost = transformer.fromGeneric({
text: 'Check out this post!',
images: ['https://example.com/image.jpg'],
hashtags: ['social', 'media']
});
// From blog post
const carouselPost = transformer.fromBlogPost({
title: 'My Blog Post',
excerpt: 'This is a great post about...',
content: 'Full content here',
featuredImage: 'https://example.com/featured.jpg',
images: ['https://example.com/1.jpg', 'https://example.com/2.jpg'],
tags: ['blogging', 'tutorial']
});
// Convert to story
const story = transformer.convertToStory(content);
// Convert to reel
const reel = transformer.convertToReel(content);
// Optimize for Instagram
const optimized = transformer.optimizeForInstagram(content);Fluent Builder
import { InstagramContentBuilder } from '@bernierllc/social-media-content-type-instagram';
const builder = new InstagramContentBuilder();
// Build a complete post
const post = builder
.setCaption('Amazing carousel post!')
.setPostType('carousel')
.addMedia({ type: 'image', url: 'https://example.com/1.jpg', aspectRatio: 'square' })
.addMedia({ type: 'image', url: 'https://example.com/2.jpg', aspectRatio: 'portrait' })
.addMedia({ type: 'image', url: 'https://example.com/3.jpg', aspectRatio: 'landscape' })
.addHashtags(['carousel', 'instagram', 'photos'])
.addMentions(['partner_account', 'photographer'])
.setLocation({ name: 'New York City', latitude: 40.7128, longitude: -74.0060 })
.addCollaborator('collaborator_username')
.setShareToFacebook(true)
.setAltText(['Image 1 description', 'Image 2 description', 'Image 3 description'])
.build();
// Validate before building
const validationResult = builder.validate();
if (!validationResult.valid) {
console.error('Validation errors:', validationResult.errors);
}Instagram Content Types
Feed Posts
Standard Instagram posts with 1-10 media items:
interface InstagramContent {
caption: string; // Max 2200 characters
media: InstagramMedia[]; // 1-10 items
postType: 'feed' | 'carousel' | 'story' | 'reel';
altText?: string[]; // One per media item
location?: InstagramLocation;
collaborators?: string[]; // Collab posts
productTags?: InstagramProductTag[];
}Stories (24-hour ephemeral)
interface InstagramStory {
media: InstagramMedia; // Single media item
duration: number; // 3-15 seconds
stickers?: InstagramSticker[]; // Interactive elements
link?: InstagramStoryLink; // Swipe-up (10k+ followers)
polls?: InstagramStoryPoll[];
questions?: InstagramStoryQuestion[];
countdowns?: InstagramCountdown[];
music?: InstagramMusic;
}Reels (short-form video)
interface InstagramReel {
video: InstagramMedia; // Vertical video (9:16)
caption: string; // Max 2200 characters
coverImage?: string;
audio: InstagramAudio; // Original, trending, or saved
shareToFeed: boolean;
}Carousels (multi-image posts)
Carousels support 1-10 images or videos with a shared caption:
const carousel = builder
.setCaption('Swipe to see more!')
.addMediaBatch([
{ type: 'image', url: 'https://example.com/1.jpg', aspectRatio: 'square' },
{ type: 'image', url: 'https://example.com/2.jpg', aspectRatio: 'square' },
{ type: 'video', url: 'https://example.com/vid.mp4', aspectRatio: 'square' }
])
.build();Instagram Constraints
import { INSTAGRAM_CONSTRAINTS } from '@bernierllc/social-media-content-type-instagram';
// Caption limits
INSTAGRAM_CONSTRAINTS.maxCaptionLength // 2200
INSTAGRAM_CONSTRAINTS.captionPreviewLength // 125 (before "more...")
// Hashtag limits
INSTAGRAM_CONSTRAINTS.maxHashtags // 30
INSTAGRAM_CONSTRAINTS.recommendedHashtagsMin // 3
INSTAGRAM_CONSTRAINTS.recommendedHashtagsMax // 5
// Media limits
INSTAGRAM_CONSTRAINTS.maxCarouselItems // 10
INSTAGRAM_CONSTRAINTS.maxMentions // 20
// Story/Reel durations
INSTAGRAM_CONSTRAINTS.minStoryDuration // 3 seconds
INSTAGRAM_CONSTRAINTS.maxStoryDuration // 15 seconds
INSTAGRAM_CONSTRAINTS.minReelDuration // 3 seconds
INSTAGRAM_CONSTRAINTS.maxReelDuration // 90 seconds
// Aspect ratios
INSTAGRAM_CONSTRAINTS.imageDimensions.square // 1080x1080
INSTAGRAM_CONSTRAINTS.imageDimensions.portrait // 1080x1350
INSTAGRAM_CONSTRAINTS.imageDimensions.landscape // 1080x566
INSTAGRAM_CONSTRAINTS.imageDimensions.story // 1080x1920
INSTAGRAM_CONSTRAINTS.imageDimensions.reel // 1080x1920Utility Classes
AspectRatioOptimizer
import { AspectRatioOptimizer } from '@bernierllc/social-media-content-type-instagram';
const optimizer = new AspectRatioOptimizer();
// Determine optimal ratio from dimensions
const ratio = optimizer.determineOptimalRatio(1080, 1350);
// Returns: 'portrait'
// Calculate target dimensions
const dims = optimizer.calculateDimensions('square');
// Returns: { width: 1080, height: 1080 }
// Check if valid for post type
const valid = optimizer.isValidForPostType('story', 'story');
// Returns: trueStoryConverter
import { StoryConverter } from '@bernierllc/social-media-content-type-instagram';
const converter = new StoryConverter();
// Convert content to story
const story = converter.convertToStory(content);
// Create story with stickers
const interactiveStory = converter.createStoryWithStickers(media, {
hashtags: ['instagram', 'stories'],
mentions: ['username'],
location: 'New York City'
});ReelConverter
import { ReelConverter } from '@bernierllc/social-media-content-type-instagram';
const converter = new ReelConverter();
// Convert content to reel
const reel = converter.convertToReel(content, 'trending');
// Create reel with audio
const customReel = converter.createReelWithAudio(
videoMedia,
'Check out this reel!',
{ type: 'trending', audioId: '12345', audioName: 'Trending Song' },
{ coverImage: 'https://example.com/cover.jpg', shareToFeed: true }
);CarouselCreator
import { CarouselCreator } from '@bernierllc/social-media-content-type-instagram';
const creator = new CarouselCreator();
// Create carousel
const carousel = creator.createCarousel(mediaArray, 'My carousel!');
// Add media
const updated = creator.addMedia(carousel, newMedia);
// Remove media
const removed = creator.removeMedia(carousel, 1);
// Reorder media
const reordered = creator.reorderMedia(carousel, 0, 2);HashtagOptimizer
import { HashtagOptimizer } from '@bernierllc/social-media-content-type-instagram';
const optimizer = new HashtagOptimizer();
// Extract hashtags from text
const hashtags = optimizer.extractHashtags('Post #instagram #social #media');
// Returns: ['instagram', 'social', 'media']
// Optimize count (limit to 3-5)
const optimized = optimizer.optimizeHashtags(hashtagArray, 5);
// Format for caption
const formatted = optimizer.formatHashtags(['test', 'instagram']);
// Returns: '#test #instagram'
// Validate hashtag
const valid = optimizer.validateHashtag('instagram_2025');
// Returns: true
// Suggest hashtags
const suggestions = optimizer.suggestHashtags(text, keywords);Best Practices
Hashtag Strategy
Instagram recommends 3-5 hashtags for best engagement, though the platform allows up to 30:
// Recommended
builder.addHashtags(['photography', 'sunset', 'nature']); // 3 hashtags
// Allowed but not recommended
builder.addHashtags(Array.from({ length: 30 }, (_, i) => `tag${i}`)); // 30 hashtagsCaption Preview
The first 125 characters appear before "more...". Put your key message first:
builder.setCaption(
'Key message here! Link in bio 👆\n\nAdditional details and story...'
);Aspect Ratios
Different post types support different aspect ratios:
- Feed/Carousel: Square (1:1), Portrait (4:5), Landscape (1.91:1)
- Stories: Vertical 9:16 only
- Reels: Vertical 9:16 only
Carousel Engagement
Carousels typically get higher engagement than single-image posts. Use them for storytelling:
const carousel = builder
.setCaption('Swipe to see the transformation! ➡️')
.addMediaBatch([
{ type: 'image', url: 'before.jpg', aspectRatio: 'square' },
{ type: 'image', url: 'during.jpg', aspectRatio: 'square' },
{ type: 'image', url: 'after.jpg', aspectRatio: 'square' }
])
.build();Integration Status
Logger Integration
Status: Not applicable
Justification: This is a pure content type definition package with no runtime operations, side effects, or error conditions that require logging. The InstagramContentValidator, InstagramContentBuilder, and InstagramContentTransformer classes are stateless utility classes that perform validation, building, and transformation operations. All errors are thrown as exceptions that calling code can handle, and there are no background operations, network calls, or state changes that would benefit from structured logging.
Pattern: Pure functional utility - no logger integration needed. Logging is handled by consuming packages that use this content type.
NeverHub Integration
Status: Planned
Justification: This package can optionally register itself with NeverHub for service discovery. Content type packages can register themselves with NeverHub so that services can discover available content types at runtime. This enables dynamic content type discovery and allows services to adapt to available content types without hard-coded dependencies. The registration schema is available via INSTAGRAM_CONTENT_TYPE_REGISTRATION.
Pattern: Optional service discovery integration - package can register content type with NeverHub for runtime discovery.
Example Integration:
import { INSTAGRAM_CONTENT_TYPE_REGISTRATION } from '@bernierllc/social-media-content-type-instagram';
// Register with NeverHub (if available)
if (typeof detectNeverHub === 'function') {
neverhub.registerContentType(INSTAGRAM_CONTENT_TYPE_REGISTRATION);
}Docs-Suite Integration
Status: Ready
Format: TypeDoc-compatible JSDoc comments are included throughout the source code. All public APIs are documented with examples and type information.
Dependencies
- @bernierllc/crypto-utils (^1.0.2) - Media hash generation
- validator (^13.12.0) - URL and string validation
Related Packages
- @bernierllc/social-media-content-type-twitter - Twitter/X content types
- @bernierllc/social-media-content-type-linkedin - LinkedIn content types
- @bernierllc/social-media-content-type-bluesky - Bluesky content types
- @bernierllc/social-media-content-type-facebook - Facebook content types (pending)
- @bernierllc/social-media-content-type-mastodon - Mastodon content types (pending)
- @bernierllc/social-media-instagram (pending) - Instagram service layer
- @bernierllc/social-media-manager (pending) - Multi-platform orchestration
TypeScript Support
This package is written in TypeScript and includes complete type definitions:
import type {
InstagramContent,
InstagramMedia,
InstagramStory,
InstagramReel,
InstagramAspectRatio,
InstagramValidationResult,
InstagramMetadata,
InstagramConstraints
} from '@bernierllc/social-media-content-type-instagram';Testing
This package includes comprehensive tests with 98%+ coverage:
npm test # Run tests in watch mode
npm run test:run # Run tests once
npm run test:coverage # Run tests with coverage reportBuilding
npm run build # Compile TypeScript to dist/
npm run clean # Remove dist/ directory
npm run lint # Run ESLintLicense
Copyright (c) 2025 Bernier LLC. All rights reserved.
This package is part of the BernierLLC Content Management Suite and is licensed under a limited-use license. See LICENSE file for details.
