Skip to content

React Native Image Compression KitControl image bytes before upload

Bound upload payloads and app-owned image files with explicit native capabilities, resource limits, cancellation, metadata policy, and output ownership.

Image Compression Kit logo

Why device-side bytes matter

Ericsson reports that average mobile data traffic reached 22 GB per active smartphone per month at the end of 2025 and forecasts mobile data traffic, excluding fixed wireless access, to reach 328 EB per month in 2031. This is market context—not a package savings claim. Review the source and forecast limits.

Image cost has two surfaces: bytes that move from the device and app-owned files that remain in queues, outputs, caches, and residual storage.

Upload economics for moving bytes and device-storage economics for app-owned bytes at rest

Upload

≈ 3.5 TB

1M accepted images · 4 MB → 500 KB

App-owned queue

800 → 100 MB

200 replaceable staging images

Accurate boundary

Source unchanged

Gallery files are never removed

The figures are decimal-unit arithmetic examples, not measured performance or guaranteed cost reduction. Source and output can temporarily coexist; copied or durable files remain the host application's responsibility.

A small, explicit boundary

Check

Ask the runtime for codecs, policies, and limits.

Bound

Compress under byte, pixel, metadata, and cancellation rules.

Release

Upload the verified result, then remove the owned cache output.

Android 23+File and content URIs with device-gated codecs.
iOS 13.4+ImageIO-backed input and runtime-gated WebP output.
Expo dev buildCustom native code requires prebuild; Expo Go is unsupported.

Current release: 0.4.0 is published on npm latest. The immutable tag, GitHub Release, registry provenance, and retained evidence all bind the same verified artifact and source.

Known iOS issue: v0.4.0 can vertically invert pixels after ImageIO normalizes an orientation-bearing input. The 0.4.1 source candidate fixes the renderer and adds EXIF 1–8 plus capture-time visual-agreement gates. The old iOS capture is retained as affected evidence, not presented as a passing visual result.

Evidence, not adjectives

v0.4.0 evidence snapshot: one of two native captures passes the combined byte-budget and visual-integrity gate because the retained iOS capture is orientation-affected; zero residual-output target, two capability captures, 96 percent fewer planned decoded pixels, zero of seven named sensitive fields retained, and eight of eight packed-consumer platform builds passed.

The scorecard separates measured fixture and release evidence from broader claims the project does not yet make. Review the metric definitions and interpretation limits before comparing results.

Install

bash
npm install react-native-image-compression-kit
ts
import {
  compressImage,
  getImageCompressionCapabilities,
} from 'react-native-image-compression-kit';

const capabilities = await getImageCompressionCapabilities();
const canWriteWebP = capabilities.formats.some(
  item => item.format === 'webp' && item.output
);

const result = await compressImage({
  source: { uri: imageUri },
  resize: { maxWidth: 2048, maxHeight: 2048, mode: 'contain' },
  output: {
    format: canWriteWebP ? 'webp' : 'jpeg',
    quality: 90,
    maxBytes: 500_000,
  },
  metadata: 'safe',
});

const accepted = result.byteSize <= 500_000;
if (!accepted) throw new Error('Image did not meet the upload policy');
await upload(result.uri);

removeCompressionOutput(result.uri) is available in the 0.4.1 repository candidate, not npm 0.4.0. Until it is published, clean successful outputs with the host application's file API after upload or copy.

The source must be a local URI available to native code. Remote URLs and data URIs are intentionally outside the package scope.

Configuration builder

Generate capability-aware code

This builder produces React Native code. It does not compress an image in your browser.

React Native
const requestedFormat = 'webp' as const;
const capabilities = await getImageCompressionCapabilities();
const canWrite = capabilities.formats.some(
  item => item.format === requestedFormat && item.output
);
const outputFormat = canWrite ? requestedFormat : 'jpeg';

const result = await compressImage({
  source: { uri: imageUri },
  resize: { maxWidth: 2048, mode: 'contain' },
  output: { format: outputFormat, quality: 80, maxBytes: 500000 },
  metadata: 'safe',
});

From problem to integration

Start with the byte economics and measurement guide to decide what your application should measure. Then choose a compression recipe, build a request with the option builder above, and confirm runtime capabilities.

The native result explorer remains reproducible evidence that the Android and iOS example apps execute the contract. It is supporting proof, not the product's reason to exist, and it does not substitute a browser codec for the native pipeline.

Native output claims are capability-driven and evidence-backed.