Substack handles most image formats without much fuss, but there are format and dimension decisions that affect how your newsletter looks in email inboxes (Gmail, Apple Mail, Outlook) versus the web reader versus the app. Images optimized for social sharing often aren't optimized for email, and vice versa. This guide covers the full range of file types Substack supports and how to prep them for consistent rendering across all delivery channels.

Substack file specifications

Based on Substack's image requirements and platform testing:

Images

  • Accepted formats: JPEG, PNG, GIF (animated supported), WebP
  • Maximum file size: 20 MB per image upload
  • Maximum dimensions: No stated pixel cap, but Substack auto-resizes images wider than the content column (approximately 1170px wide on desktop)
  • Recommended post image width: 1200 px wide. Substack's content column is ~700–1170 px depending on layout; images are downscaled to fit.
  • Social preview image (Open Graph): 1200×630 px (16:9 ratio). The first image in a post, or the uploaded cover image, is used as the OG preview when shared on social media.
  • Email rendering width: Approximately 600px in most email clients. Substack scales down images for email. Upload at 1200px wide to ensure sharp rendering in email at 2x (retina) and 1x.
  • Profile/publication avatar: 256×256 px minimum, square (1:1), JPEG or PNG

Audio (Podcast posts)

  • Accepted formats: MP3
  • Maximum file size: 500 MB per audio upload
  • Recommended bitrate: 128–192 kbps; 192 kbps mono for voice podcasts
  • Substack hosts and streams audio directly — no third-party podcast host needed for Substack-native podcasts

Video

  • Direct upload: MP4 (H.264), MOV, AVI, WMV, FLV, MKV — up to 5 GB
  • Recommended: MP4, H.264, 1080p (1920×1080) or 720p (1280×720)
  • Embeds: YouTube and Vimeo URLs can be pasted directly into the editor and render as embedded players
  • Note: Direct video upload is available on paid plans; free Substack accounts use YouTube/Vimeo embeds

File attachments

  • Not natively supported. Substack doesn't offer general file attachment (PDF, ZIP, etc.) hosting. Use a file sharing service (Google Drive, Dropbox, S3) and link to the file in the post.
SourceSituationTargetNotes
PNG (screenshots, diagrams)Charts, UI screenshots, step-by-step screenshotsPNG or WebPKeep PNG for screenshots with text — JPEG artifacts make text look blurry; WebP is 30% smaller
TIFF (photo retouching output)Professional photography for editorial newslettersJPEGTIFF not accepted; convert to JPEG 85–90% quality; 1200 px wide is sufficient
HEIC (iPhone photos)Behind-the-scenes or travel content from iPhoneJPEGHEIC not accepted by Substack uploader; convert before uploading
RAW photo (DSLR)High-quality editorial photographyJPEGExport from Lightroom/Capture One at 1200px wide, sRGB, 85% quality
MP4 (H.265/HEVC)Screen recordings from modern Mac (HEVC default)MP4 (H.264)Substack's video player may not handle HEVC; transcode to H.264 for broad compatibility
MOV (iPhone/DSLR)Short videos for post header or tutorialMP4MOV technically accepted but MP4 H.264 uploads more reliably and plays in all email clients
WAV/AIFF (podcast recording)Edited podcast episode for Substack audio postMP3 192kbpsSubstack only accepts MP3 for audio; convert from lossless source

Conversion commands (curl + Python)

# curl — convert HEIC photo to JPEG for Substack
curl -X POST https://changethisfile.com/v1/convert \
  -H "Authorization: Bearer ctf_sk_your_key_here" \
  -F "file=@photo.heic" \
  -F "target=jpg" \
  -o substack-photo.jpg

# Convert PNG diagram to WebP (smaller, faster load in web reader)
curl -X POST https://changethisfile.com/v1/convert \
  -H "Authorization: Bearer ctf_sk_your_key_here" \
  -F "file=@diagram.png" \
  -F "target=webp" \
  -o diagram.webp

# Convert WAV podcast audio to MP3 for Substack audio post
curl -X POST https://changethisfile.com/v1/convert \
  -H "Authorization: Bearer ctf_sk_your_key_here" \
  -F "file=@episode.wav" \
  -F "target=mp3" \
  -o episode-substack.mp3
import requests
from pathlib import Path

API_KEY = "ctf_sk_your_key_here"

def convert_for_substack(in_path: str, out_path: str, target: str) -> None:
    """Convert a file to Substack-compatible format."""
    with open(in_path, "rb") as f:
        resp = requests.post(
            "https://changethisfile.com/v1/convert",
            headers={"Authorization": f"Bearer {API_KEY}"},
            files={"file": f},
            data={"target": target},
            timeout=300,
        )
    resp.raise_for_status()
    out = Path(out_path)
    out.write_bytes(resp.content)
    kb = len(resp.content) / 1024
    print(f"{out.name}: {kb:.0f} KB")

# Image: HEIC → JPEG
convert_for_substack("photo.heic", "substack-photo.jpg", "jpg")
# Audio: WAV → MP3
convert_for_substack("episode.wav", "episode.mp3", "mp3")
# Video: MOV → MP4
convert_for_substack("clip.mov", "clip.mp4", "mp4")

For precise 1200px width with optimized compression for email delivery:

# ImageMagick: resize to 1200px wide, JPEG 85% quality (email-optimized)
convert source.tiff \
  -resize '1200x>' \
  -quality 85 \
  substack-header.jpg

# FFmpeg: transcode HEVC video to H.264 MP4 for Substack
ffmpeg -i screen-recording.mov \
  -c:v libx264 -crf 22 -preset fast \
  -c:a aac -b:a 128k \
  -vf "scale=1920:1080:force_original_aspect_ratio=decrease" \
  clip-substack.mp4

Batch script: prep a newsletter's media folder

#!/usr/bin/env bash
# Usage: ./convert_substack_batch.sh ./raw-media ./substack-ready [image|audio|video]
# Converts images (HEIC/TIFF/WebP), audio (WAV/AIFF), or video (MOV/MKV) for Substack

API_KEY="ctf_sk_your_key_here"
INPUT_DIR="${1:-.}"
OUTPUT_DIR="${2:-./substack-ready}"
MODE="${3:-image}"  # image, audio, or video

mkdir -p "$OUTPUT_DIR"
success=0; failed=0

if [ "$MODE" = "audio" ]; then
  EXTS=("wav" "WAV" "aiff" "AIFF" "flac" "FLAC" "m4a")
  TARGET="mp3"
elif [ "$MODE" = "video" ]; then
  EXTS=("mov" "MOV" "mkv" "MKV" "avi" "AVI" "wmv" "webm")
  TARGET="mp4"
else
  EXTS=("heic" "HEIC" "tiff" "tif" "bmp" "BMP" "webp" "avif")
  TARGET="jpg"
fi

for ext in "${EXTS[@]}"; do
  for src in "$INPUT_DIR"/*.$ext; do
    [ -f "$src" ] || continue
    base=$(basename "$src" | sed 's/\.[^.]*$//')
    out="$OUTPUT_DIR/${base}.${TARGET}"

    printf "%-55s" "$(basename $src) → ${TARGET}..."
    code=$(curl -s -o "$out" -w "%{http_code}" \
      -X POST https://changethisfile.com/v1/convert \
      -H "Authorization: Bearer $API_KEY" \
      -F "file=@$src" \
      -F "target=$TARGET")

    if [ "$code" = "200" ]; then
      size=$(du -h "$out" | cut -f1)
      echo "OK ($size)"
      ((success++))
    else
      echo "FAILED (HTTP $code)"
      rm -f "$out"
      ((failed++))
    fi
  done
done

echo ""
echo "Mode: $MODE | Results: $success OK, $failed failed | Output: $OUTPUT_DIR"

Substack-specific gotchas

  • Email rendering width is ~600px — upload at 1200px for retina sharpness. Email clients typically render content at 600px wide. Substack automatically downscales your uploaded images. If you upload at exactly 600px, retina email clients (most modern phones) display it at half resolution — blurry. Upload at 1200px wide so the downscaled 600px version is crisp on retina displays.
  • Animated GIFs work in the web reader but not in all email clients. Gmail on Android and Outlook on Windows don't animate GIFs in email. The first frame shows as a static image. For animated content that needs to play in email, consider linking to the GIF on the web version of the post rather than embedding.
  • HEIC is not accepted by Substack's uploader. iPhone photos in HEIC format fail silently or with a generic error on Substack's image upload. Convert to JPEG before uploading — this catches most iPhone content creators off guard.
  • Substack audio posts only accept MP3. Despite supporting video in multiple formats, audio is strictly MP3. WAV, AIFF, M4A, and FLAC all fail upload. Convert to MP3 192 kbps before uploading to a podcast post.
  • The 20MB image limit is generous but watch PNGs. High-resolution PNG screenshots or lossless exports can easily exceed 20MB. Convert large PNGs to WebP (typically 70–80% smaller than PNG) or JPEG 90% quality to stay well under the limit.
  • Cover images affect social preview, not email. The cover image you set in Substack settings becomes the Open Graph image for social sharing. In email, subscribers see the first embedded image in the post body (or no image if your template doesn't include a header). Design both with their respective context in mind.
  • Free Substack accounts can't upload video directly. Direct video hosting requires a paid Substack subscription. Free accounts must use YouTube or Vimeo embed links pasted into the post editor.

Optimizing images for social sharing from Substack

When subscribers share your post on Twitter/X, LinkedIn, or iMessage, the platform fetches the Open Graph preview image. Substack uses the first uploaded image in the post (or the set cover image) as the OG image. For maximum social click-through:

  • Use 1200×630 px (16:9) for the post's first image. This is the canonical OG image size. Twitter/X, LinkedIn, and Facebook all display this ratio without cropping.
  • Avoid text at the edges. Social platforms sometimes add safe-zone padding around OG images. Keep important text and design elements within the central 1080×560 px region.
  • JPEG for photos, PNG for graphics with text. For social preview cards with text overlays or sharp graphic elements, PNG preserves quality. For photography-based headers, JPEG 90% is smaller and renders equally well.
# Create a 1200x630 social-optimized header image
convert source.jpg \
  -resize '1200x630^' \
  -gravity center -extent 1200x630 \
  -quality 88 \
  substack-social-header.jpg

Substack's format support is broad, but email rendering is the constraint that shapes all the decisions — 1200px wide images, JPEG for photos, PNG or WebP for text-heavy graphics, MP3 for audio. Getting these right once means every future post goes live looking exactly as intended across inbox and web. Free tier covers 1,000 conversions/month.