Tutorial

Mobile Screenshot Optimization: Capturing Responsive Designs Perfectly

Master mobile screenshot capture with proper viewport settings, device emulation, and responsive design testing techniques.

Asad AliAugust 10, 202411 min read

Why Mobile Screenshots Matter

Mobile traffic accounts for over 60% of global web visits. Yet most screenshot automation focuses on desktop captures, leaving mobile experience validation as an afterthought.

The reality is that mobile rendering differs significantly from desktop:

  • Different viewport dimensions and aspect ratios
  • Touch-optimized layouts with larger tap targets
  • Responsive images served at different resolutions
  • Mobile-specific navigation patterns (hamburger menus, bottom bars)
  • Font size adjustments for readability
  • Completely different content prioritization

Testing and documenting your mobile experience requires purpose-built screenshot capture that understands these differences.

Understanding Mobile Viewports

Device Pixel Ratio Explained

Modern mobile devices have high-density displays. An iPhone 15 Pro has a 3x device pixel ratio (DPR), meaning each CSS pixel is rendered with 3 physical pixels in each dimension.

When capturing screenshots:

  • DPR 1: Standard resolution, 1:1 CSS to physical pixels
  • DPR 2: Retina/2x resolution, common on tablets and older phones
  • DPR 3: Super retina/3x resolution, current flagship phones
// Standard mobile capture
const response = await fetch('https://api.screenshotly.app/screenshot', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://example.com',
    viewport: {
      width: 375,
      height: 812,
      deviceScaleFactor: 3, // iPhone 15 Pro DPR
    },
    format: 'png',
  }),
});

Common Mobile Viewport Sizes

Device Viewport DPR Physical Resolution
iPhone 15 Pro 393×852 3 1179×2556
iPhone 15 390×844 3 1170×2532
iPhone SE 375×667 2 750×1334
Pixel 8 412×915 2.625 1080×2400
Samsung S24 360×780 3 1080×2340
iPad Pro 12.9" 1024×1366 2 2048×2732
iPad Air 820×1180 2 1640×2360

Basic Mobile Screenshot Capture

Using Device Presets

The simplest approach uses our built-in device presets:

const response = await fetch('https://api.screenshotly.app/screenshot', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://example.com',
    device: 'mobile', // Uses sensible mobile defaults
    format: 'png',
  }),
});

For specific devices:

const response = await fetch('https://api.screenshotly.app/screenshot', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://example.com',
    device: 'iphone-15-pro', // Exact device emulation
    format: 'png',
  }),
});

Custom Viewport Configuration

For precise control:

const response = await fetch('https://api.screenshotly.app/screenshot', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://example.com',
    viewport: {
      width: 375,
      height: 812,
      deviceScaleFactor: 3,
      isMobile: true,          // Enables touch emulation
      hasTouch: true,          // Touch event support
      isLandscape: false,      // Portrait orientation
    },
    userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15',
    format: 'png',
  }),
});

Responsive Design Testing

Testing Multiple Breakpoints

Capture your site at all responsive breakpoints:

async function captureResponsiveBreakpoints(url) {
  const breakpoints = [
    { name: 'mobile-sm', width: 320, height: 568, dpr: 2 },
    { name: 'mobile-md', width: 375, height: 812, dpr: 3 },
    { name: 'mobile-lg', width: 428, height: 926, dpr: 3 },
    { name: 'tablet', width: 768, height: 1024, dpr: 2 },
    { name: 'tablet-lg', width: 1024, height: 1366, dpr: 2 },
    { name: 'desktop', width: 1440, height: 900, dpr: 1 },
    { name: 'desktop-lg', width: 1920, height: 1080, dpr: 1 },
  ];

  const screenshots = await Promise.all(
    breakpoints.map(async (bp) => {
      const response = await fetch('https://api.screenshotly.app/screenshot', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${process.env.SCREENSHOTLY_API_KEY}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          url,
          viewport: {
            width: bp.width,
            height: bp.height,
            deviceScaleFactor: bp.dpr,
            isMobile: bp.width < 1024,
          },
          format: 'png',
        }),
      });

      return {
        breakpoint: bp.name,
        width: bp.width,
        image: await response.arrayBuffer(),
      };
    })
  );

  return screenshots;
}

Visual Regression for Responsive

Integrate with visual testing workflows for automated testing:

// responsive-visual-test.js
const { captureResponsiveBreakpoints } = require('./screenshot-utils');

describe('Responsive Design Tests', () => {
  const pages = [
    { name: 'homepage', url: 'https://mysite.com/' },
    { name: 'pricing', url: 'https://mysite.com/pricing' },
    { name: 'blog', url: 'https://mysite.com/blog' },
  ];

  pages.forEach((page) => {
    it(`${page.name} should match responsive baselines`, async () => {
      const screenshots = await captureResponsiveBreakpoints(page.url);

      screenshots.forEach((screenshot) => {
        expect(screenshot.image).toMatchImageSnapshot({
          customSnapshotIdentifier: `${page.name}-${screenshot.breakpoint}`,
        });
      });
    });
  });
});

Handling Mobile-Specific Challenges

Mobile Navigation States

Mobile sites often have hidden menus. Capture both states:

async function captureMobileNavigation(url) {
  // Closed menu state
  const closedNav = await fetch('https://api.screenshotly.app/screenshot', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.SCREENSHOTLY_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      url,
      device: 'mobile',
      format: 'png',
    }),
  });

  // Open menu state
  const openNav = await fetch('https://api.screenshotly.app/screenshot', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.SCREENSHOTLY_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      url,
      device: 'mobile',
      format: 'png',
      beforeCapture: {
        click: '.hamburger-menu', // Click to open menu
      },
      delay: 500, // Wait for animation
    }),
  });

  return { closedNav, openNav };
}

Handling Mobile Popups

Mobile-specific popups require AI removal:

const response = await fetch('https://api.screenshotly.app/screenshot', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://example.com',
    device: 'mobile',
    format: 'png',
    aiRemoval: {
      enabled: true,
      types: ['cookie-banner', 'app-install', 'newsletter'],
    },
  }),
});

The app-install type specifically targets mobile-only app download banners that appear at the top or bottom of mobile sites.

Scroll Position and Fold Content

Capture content below the fold:

// Capture specific scroll positions
async function captureScrollSequence(url) {
  const positions = [0, 500, 1000, 1500, 2000];

  const captures = await Promise.all(
    positions.map(async (scrollY) => {
      const response = await fetch('https://api.screenshotly.app/screenshot', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${process.env.SCREENSHOTLY_API_KEY}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          url,
          device: 'mobile',
          format: 'png',
          scrollTo: scrollY,
          delay: 300, // Allow lazy-loaded content
        }),
      });

      return {
        position: scrollY,
        image: await response.arrayBuffer(),
      };
    })
  );

  return captures;
}

Full-Page Mobile Capture

For complete page documentation:

const response = await fetch('https://api.screenshotly.app/screenshot', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://example.com',
    device: 'mobile',
    fullPage: true,
    format: 'png',
    aiRemoval: {
      enabled: true,
      types: ['cookie-banner', 'chat-widget', 'app-install'],
    },
  }),
});

Portrait vs Landscape

Orientation Capture

// Portrait capture
const portrait = await fetch('https://api.screenshotly.app/screenshot', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.SCREENSHOTLY_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://example.com',
    viewport: {
      width: 375,
      height: 812,
      isLandscape: false,
    },
    format: 'png',
  }),
});

// Landscape capture (swap width/height)
const landscape = await fetch('https://api.screenshotly.app/screenshot', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.SCREENSHOTLY_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://example.com',
    viewport: {
      width: 812,
      height: 375,
      isLandscape: true,
    },
    format: 'png',
  }),
});

When to Use Landscape

  • Video player pages
  • Data-heavy dashboards
  • Image galleries
  • Games and interactive content
  • Comparison tables

Device Mockups for Mobile

Combine mobile captures with device mockups:

const response = await fetch('https://api.screenshotly.app/screenshot', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://your-app.com',
    device: 'mobile',
    format: 'png',
    mockup: 'iphone-15-pro',
    mockupOptions: {
      color: 'natural-titanium',
      shadow: true,
      background: 'transparent',
    },
    aiRemoval: {
      enabled: true,
      types: ['cookie-banner', 'chat-widget'],
    },
  }),
});

Documentation Workflow

Creating Mobile Documentation

For documentation screenshots of mobile features:

async function documentMobileFeature(feature) {
  const steps = [
    { url: feature.enterUrl, name: 'entry' },
    { url: feature.actionUrl, name: 'action' },
    { url: feature.resultUrl, name: 'result' },
  ];

  const docs = await Promise.all(
    steps.map(async (step) => {
      const response = await fetch('https://api.screenshotly.app/screenshot', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${process.env.SCREENSHOTLY_API_KEY}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          url: step.url,
          device: 'iphone-15',
          format: 'png',
          mockup: 'iphone-15',
          aiRemoval: {
            enabled: true,
            types: ['cookie-banner', 'chat-widget'],
          },
        }),
      });

      return {
        step: step.name,
        image: await response.arrayBuffer(),
      };
    })
  );

  return docs;
}

Performance Considerations

Optimizing Mobile Captures

Mobile captures can be faster due to smaller viewports:

// Optimized mobile capture configuration
const response = await fetch('https://api.screenshotly.app/screenshot', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://example.com',
    viewport: {
      width: 375,
      height: 667,
      deviceScaleFactor: 1, // Lower DPR for speed
    },
    format: 'jpeg',
    quality: 80, // Good balance
    blockResources: ['font'], // Optional: skip web fonts
    timeout: 15000,
  }),
});

For more optimization techniques, see our performance guide.

Batch Mobile Testing

Efficiently test multiple devices:

async function batchMobileTest(url) {
  const devices = [
    { name: 'iphone-se', preset: 'iphone-se' },
    { name: 'iphone-15', preset: 'iphone-15' },
    { name: 'iphone-15-pro-max', preset: 'iphone-15-pro-max' },
    { name: 'pixel-8', preset: 'pixel-8' },
    { name: 'samsung-s24', preset: 'samsung-s24' },
  ];

  // Parallel capture with rate limiting
  const batchSize = 3;
  const results = [];

  for (let i = 0; i < devices.length; i += batchSize) {
    const batch = devices.slice(i, i + batchSize);
    const batchResults = await Promise.all(
      batch.map((device) =>
        captureDevice(url, device.preset).then((r) => ({
          device: device.name,
          image: r,
        }))
      )
    );
    results.push(...batchResults);
  }

  return results;
}

Best Practices Summary

  1. Match real device specs - Use accurate viewport and DPR values
  2. Test all breakpoints - Don't assume mobile means one size
  3. Handle mobile-specific popups - Use app-install AI removal
  4. Consider orientation - Some content requires landscape
  5. Use device mockups - For professional marketing materials
  6. Optimize for speed - Mobile viewports render faster

Next Steps

Explore our JavaScript or Python integration guides for language-specific implementations.

Ready to perfect your mobile screenshots? Try configurations in our playground or get started free.

mobile
responsive
viewport
testing

About the Author

Asad Ali

Asad Ali

Full-Stack Developer and Founder of ZTabs with 8+ years of experience building scalable web applications and APIs. Specializes in performance optimization, SaaS development, and modern web technologies.

Credentials: Founder & CEO at ZTabs, Full-Stack Developer, Expert in Next.js, React, Node.js, and API optimization

Frequently Asked Questions

What mobile viewports does Screenshotly support?

Screenshotly supports any custom viewport size you specify. We also provide preset device emulations for iPhone (all generations), Android phones (Pixel, Samsung), and tablets (iPad, Android tablets) with accurate viewport and device pixel ratio settings.

How do I capture retina-quality mobile screenshots?

Set the deviceScaleFactor to 2 or 3 in your viewport configuration. This captures at 2x or 3x resolution, matching the pixel density of modern mobile displays.

Can I test responsive breakpoints automatically?

Yes! Capture the same URL at multiple viewport widths to test your responsive breakpoints. Common widths are 375px (mobile), 768px (tablet), 1024px (small desktop), and 1440px (large desktop).

How do I handle mobile-specific content like app install banners?

Use our AI removal feature with the 'app-install' type to automatically hide app install prompts that only appear on mobile.

Ready to capture your first screenshot?

Get started with 100 free screenshots. No credit card required.

Related Articles