Skip to main content
Create rich, diverse content by combining different media types in a single post. Mix images, videos, audio files, and documents to create engaging multimedia experiences.

Multiple Media Types

Combine images, videos, audio, and files in one post

Up to 10 Attachments

Mix and match up to 10 media items of any type

Overview

Mixed media posts enable creators to share diverse content without splitting into multiple posts:
  • Flexible Combinations: Mix images + videos + audio + files
  • Single Post Structure: Keep related content together
  • Unified Engagement: Users interact with one cohesive post

Post Structure Types

Every post now has a structureType field that describes its media composition:
Structure TypeDescriptionExample
textContains only text content, no attachmentsText-only announcement or discussion
imageContains only image attachmentsPhoto gallery with 3 images
videoContains only video attachmentsVideo post with 2 clips
audioContains only audio attachmentsPodcast episode or voice message
fileContains only file attachmentsDocument sharing (PDFs, docs)
liveStreamContains only live stream contentLive broadcast session
pollContains only poll contentSurvey or voting post
clipContains only short-form video clipsShort video content (up to 15 min)
Pure type posts maintain backward compatibility with existing filtering behavior.
Structure Type: mixedA post is classified as mixed when it contains attachments of 2 or more distinct media types (image, video, audio, file).Examples:
  • Image + Video = mixed
  • Image + Audio = mixed
  • Video + File = mixed
  • Image + Video + Audio + File = mixed
The structureType is automatically determined when you create or edit a post. You don’t need to specify it manually. Special post types like poll, liveStream, and clip are not combined into mixed posts.
Structure Type: null or absentSome older posts or text-only posts may not have a structureType value. This is equivalent to the text structure type for backward compatibility.

Structure Type Determination

The system automatically determines the structureType based on your attachments:
// Automatic structureType assignment examples

// Example 1: Pure image post
attachments: [
  { fileId: "img1", type: "image" },
  { fileId: "img2", type: "image" }
]
// Result: structureType = "image"

// Example 2: Mixed media post
attachments: [
  { fileId: "img1", type: "image" },
  { fileId: "vid1", type: "video" }
]
// Result: structureType = "mixed"

// Example 3: Audio with image (always mixed)
attachments: [
  { fileId: "img1", type: "image" },
  { fileId: "aud1", type: "audio" }
]
// Result: structureType = "mixed"

// Example 4: Text-only post
attachments: []
// Result: structureType = null (no value)

Requirements & Limits

RequirementLimitNotes
Total AttachmentsMaximum 10 itemsAll media types combined
Media Typesimage, video, audio, fileCan mix any combination
File SizeVaries by typeImages: 100MB, Videos: varies, Audio: 1GB, Files: 1GB
Text10,000 charactersOptional caption
All media files must be uploaded before creating the post. Each media type has its own upload endpoint. See upload guides for Images, Videos, Audio, and Files.

Quick Start

1

Upload Media Files

Upload your media files using the appropriate endpoints for each type
2

Build Mixed Media Post

Use the AmityMixedMediaPostBuilder to combine different media types
3

Create Post

Create the post with all attachments in a single request
4

Handle Response

The post includes parent and child posts with automatic structureType assignment

Parameters

ParameterTypeRequiredDescription
textStringCaption text (max 10,000 characters)
attachmentsArrayMixed array of media items (max 10 total)
targetTypeEnumTarget type (user or community)
targetIdStringTarget ID (userId or communityId)
metadataObjectCustom metadata

Implementation

func createMixedMediaPost(
    images: [AmityImageData],
    videos: [AmityVideoData],
    audios: [AmityAudioData],
    files: [AmityFileData],
    text: String
) async {
    // Use the MixedMediaPostBuilder to combine different media types
    let builder = AmityMixedMediaPostBuilder()
    builder.setText(text)
    
    // Add different media types
    // The order you set them is maintained in the final post
    builder.setImages(images)
    builder.setVideos(videos)
    builder.setAudios(audios)
    builder.setFiles(files)
    
    do {
        let post = try await postRepository.createMixedMediaPost(
            builder,
            targetId: "community123",
            targetType: .community,
            metadata: nil,
            mentionees: nil
        )
        
        print("Mixed media post created!")
    } catch {
        print("Failed to create mixed media post: \(error)")
    }
}

// Example: Complete workflow with uploads
func uploadAndCreateMixedPost() async {
    do {
        // Step 1: Upload different media types
        let imageData = try await fileRepository.uploadImage(
            with: imageUrl,
            progress: { progress in
                print("Image upload: \(progress * 100)%")
            }
        )
        
        let audioData = try await fileRepository.uploadAudio(
            with: audioUrl,
            progress: { progress in
                print("Audio upload: \(progress * 100)%")
            }
        )
        
        let videoData = try await fileRepository.uploadVideo(
            with: videoUrl,
            progress: { progress in
                print("Video upload: \(progress * 100)%")
            }
        )
        
        // Step 2: Create mixed media post
        let builder = AmityMixedMediaPostBuilder()
        builder.setText("Check out this amazing content!")
        builder.setImages([imageData])
        builder.setAudios([audioData])
        builder.setVideos([videoData])
        
        let post = try await postRepository.createMixedMediaPost(
            builder,
            targetId: nil,
            targetType: .user,
            metadata: nil,
            mentionees: nil
        )
        
        print("Complete! Mixed post created with structureType: \(post.structureType ?? "mixed")")
    } catch {
        print("Error: \(error)")
    }
}
Attachment Order Preservation: The AmityMixedMediaPostBuilder maintains the order in which you add attachments. Set media in the order you want them displayed.

Structure Type Behavior

Automatic Classification

The system automatically classifies posts based on their attachments:
  • Pure Types
  • Mixed Types
Single media type only
// Example: Pure image post
attachments: [
  { type: "image", fileId: "img1" },
  { type: "image", fileId: "img2" },
  { type: "image", fileId: "img3" }
]
// structureType = "image"

// Example: Pure video post
attachments: [
  { type: "video", fileId: "vid1" }
]
// structureType = "video"

Editing Posts

When you edit a post and change its attachments, the structureType is automatically updated:
// Original post: Pure image
attachments: [
  { type: "image", fileId: "img1" }
]
// structureType = "image"

// After edit: Add a video
attachments: [
  { type: "image", fileId: "img1" },
  { type: "video", fileId: "vid1" }
]
// structureType = "mixed" (automatically updated)
Important: When editing posts, the structureType is recalculated based on the final set of attachments. This includes both active and soft-deleted child posts, so removing media may not change the structure type immediately.

Querying Mixed Media Posts

Use the includeMixedStructure parameter to control whether mixed media posts appear in your query results:
Pure type filtering - excludes mixed posts
// Query for image posts only
const posts = await PostRepository.getPosts({
  dataTypes: ['image'],
  includeMixedStructure: false // default
});

// Returns:
// ✅ Pure image posts (structureType = "image")
// ❌ Mixed posts (structureType = "mixed") - EXCLUDED even if they contain images
This preserves legacy behavior where single-type filters return only “pure” posts of that type.
Inclusive filtering - includes mixed posts containing the requested type
// Query for image posts INCLUDING mixed posts with images
const posts = await PostRepository.getPosts({
  dataTypes: ['image'],
  includeMixedStructure: true
});

// Returns:
// ✅ Pure image posts (structureType = "image")
// ✅ Mixed posts containing images (structureType = "mixed")
Useful when you want to show all posts containing a specific media type, regardless of whether they also contain other types.
Multi-type filtering - mixed posts automatically included
// Query for image OR video posts
const posts = await PostRepository.getPosts({
  dataTypes: ['image', 'video']
  // includeMixedStructure doesn't matter here
});

// Returns:
// ✅ Pure image posts (structureType = "image")
// ✅ Pure video posts (structureType = "video")
// ✅ Mixed posts (structureType = "mixed") - automatically included
When querying for multiple types, mixed posts are always relevant and included.
For detailed filtering documentation, see Post Retrieval.

Best Practices

  • Keep related content together: Use mixed media for content that tells a single story
  • Maintain logical order: Add attachments in the order users should view them
  • Use appropriate combinations: Match media types to your content needs
  • Consider user experience: Don’t overwhelm with too many different types
// Good: Tutorial post with related media
const tutorialPost = {
  text: "How to make perfect coffee ☕",
  attachments: [
    { type: "image", fileId: "step1_img" },  // Step 1 photo
    { type: "video", fileId: "demo_video" }, // Demo video
    { type: "file", fileId: "recipe_pdf" },  // Detailed recipe
    { type: "audio", fileId: "tips_audio" }  // Pro tips audio
  ]
};
  • Upload in parallel: Upload different media types simultaneously
  • Validate before upload: Check file sizes and formats client-side
  • Show progress: Display upload progress for each media type
  • Handle failures gracefully: Implement retry logic for individual uploads
  • Cache uploads: Store uploaded file IDs to avoid re-uploading
// Example: Parallel uploads with progress tracking
async function uploadAllMedia(files: MediaFiles) {
  const uploads = await Promise.allSettled([
    uploadImage(files.image, onImageProgress),
    uploadVideo(files.video, onVideoProgress),
    uploadAudio(files.audio, onAudioProgress),
  ]);
  
  // Filter successful uploads
  const successful = uploads
    .filter(result => result.status === 'fulfilled')
    .map(result => result.value);
  
  if (successful.length < uploads.length) {
    handlePartialFailure(successful, uploads);
  }
  
  return successful;
}
  • Preview all media: Let users preview all attachments before posting
  • Support reordering: Allow users to change attachment order
  • Clear media indicators: Show media type icons/badges
  • Handle missing media: Gracefully handle cases where media fails to load
  • Provide editing controls: Allow users to remove/replace individual items
// Example: Media preview component
const MixedMediaPreview = ({ attachments }) => (
  <div className="media-preview-grid">
    {attachments.map((item, index) => (
      <MediaPreviewCard
        key={index}
        type={item.type}
        fileId={item.fileId}
        onRemove={() => removeAttachment(index)}
        onReorder={(newIndex) => reorderAttachment(index, newIndex)}
      />
    ))}
  </div>
);
  • Limit total items: Stay within 10 attachment limit
  • Balance media types: Don’t overload with one type
  • Consider load time: More attachments = longer load time
  • Optimize file sizes: Compress media before upload
  • Use appropriate quality: Match quality to content importance
// Example: Validate mixed media before posting
function validateMixedMedia(attachments: Attachment[]): ValidationResult {
  if (attachments.length > 10) {
    return { valid: false, error: 'Maximum 10 attachments allowed' };
  }
  
  const typeCounts = countByType(attachments);
  if (typeCounts.image > 8) {
    return { valid: false, error: 'Consider creating an image album instead' };
  }
  
  const totalSize = calculateTotalSize(attachments);
  if (totalSize > 500 * 1024 * 1024) { // 500MB
    return { valid: false, error: 'Total size too large, compress media' };
  }
  
  return { valid: true };
}

Troubleshooting

Problem: Cannot add more than 10 attachmentsSolution:
  • Remove some attachments to stay within limit
  • Split content into multiple posts if needed
  • Prioritize most important media
if (attachments.length > 10) {
  showError('Maximum 10 attachments allowed per post');
  // Suggest splitting into multiple posts
  suggestMultiplePosts(attachments);
}
Problem: Some media uploads fail while others succeedSolution:
  • Track upload status for each media type separately
  • Retry failed uploads individually
  • Allow users to post with successful uploads only
  • Provide clear feedback on which uploads failed
const results = await Promise.allSettled(uploads);
const failed = results.filter(r => r.status === 'rejected');

if (failed.length > 0) {
  const failedTypes = failed.map(f => f.type).join(', ');
  showError(`Failed to upload: ${failedTypes}. Retry or post without them?`);
}
Problem: Post has unexpected structureTypeSolution:
  • Verify attachment types in your request
  • Check if deleted children are affecting classification
  • Remember: any combination with audio = mixed
  • Review automatic classification rules
// Debug structure type
console.log('Attachments:', post.attachments);
console.log('Structure Type:', post.structureType);
console.log('Children:', post.children.map(c => c.dataType));

// Verify classification
const expected = calculateExpectedStructureType(post.attachments);
if (expected !== post.structureType) {
  console.warn('Unexpected structure type - check for deleted children');
}
Problem: Mixed posts not appearing in filtered queriesSolution:
  • Set includeMixedStructure: true for single-type queries
  • Understand default filtering excludes mixed posts
  • Use multiple type queries to automatically include mixed posts
// If you want ALL posts with images (including mixed):
const posts = await getPosts({
  dataTypes: ['image'],
  includeMixedStructure: true // ← Important!
});

// Or query for multiple types (mixed auto-included):
const posts = await getPosts({
  dataTypes: ['image', 'video'] // mixed posts auto-included
});
Backward Compatibility: Existing single-type post creation methods (createImagePost, createVideoPost, etc.) continue to work unchanged. Mixed media posts are an additive feature that doesn’t break existing functionality.

Common Use Cases

Product Showcases

Combine product photos, demo videos, spec sheets (PDFs), and audio reviews

Event Coverage

Share event photos, highlight videos, attendee interviews (audio), and schedules (files)

Educational Content

Mix tutorial images, demo videos, downloadable resources, and audio explanations

Portfolio Pieces

Showcase work with images, process videos, case study PDFs, and client testimonials (audio)

News Articles

Combine article images, video clips, interview audio, and related documents

Travel Stories

Share photos, video clips, voice narration, and travel guides (PDFs)