@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-postFeatures
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=30Instagram 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']); // trueCaption 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
- @bernierllc/content-type-image - Base image type
- @bernierllc/content-type-registry - Content type registration
- @bernierllc/social-media-publisher - Cross-platform publishing (future)
- @bernierllc/content-management-suite - Complete content management
Support
For issues or questions, contact Bernier LLC.
