# Old Photo Restoration: Colorize, Restore Faces & Upscale (`jumblemog/old-photo-restoration`) Actor

Restore old photos with AI: colorize black-and-white and sepia photos (DDColor), restore blurry faces (GFPGAN v1.4) and upscale small scans 2x or 4x (Real-ESRGAN). Works with photo links, Google Drive, Dropbox and uploads. No API key needed.

- **URL**: https://apify.com/jumblemog/old-photo-restoration.md
- **Developed by:** [Jumble Mog](https://apify.com/jumblemog) (community)
- **Categories:** AI, For creators, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Old Photo Restoration: Colorize, Restore Faces & Upscale

Bring old family photos back to life. This Actor **colorizes black-and-white and sepia photos**, **restores blurry and damaged faces** and **upscales small scans** in one step, using three of the best open AI models for the job: [DDColor](https://github.com/piddnad/DDColor) for colorization, [GFPGAN v1.4](https://github.com/TencentARC/GFPGAN) for faces and [Real-ESRGAN](https://github.com/xinntao/Real-ESRGAN) for upscaling. Everything runs inside the Actor, so there's no API key to bring and your photos aren't sent to another AI service.

![A 1943 black-and-white wedding photo, before and after restoration](https://api.apify.com/v2/key-value-stores/Km5b4PG3kYHdZSb1E/records/old-photo-restoration-wedding.jpg?signature=pun4zSYis642y7bgmTHe)

![A 1940s family portrait with eight people, colorized with every face restored](https://api.apify.com/v2/key-value-stores/Km5b4PG3kYHdZSb1E/records/old-photo-restoration-family.jpg?signature=1QijGHdUKYwkKv30QfhWh)

![Dorothea Lange's Migrant Mother (1936), colorized and restored](https://api.apify.com/v2/key-value-stores/Km5b4PG3kYHdZSb1E/records/old-photo-restoration-migrant-mother.jpg?signature=1LPRyZynnZdR27VgOWyYV)

*Sample photos: Library of Congress, Farm Security Administration/Office of War Information collection (public domain). The first one is the Actor's example input.*

### What it does

- **Colorizes black-and-white photos** with natural skin tones, clothing and backgrounds. Sepia, cyanotype and other single-tone prints are detected and colorized too; color photos are left alone unless you ask for it.
- **Restores faces**: every face is found, rebuilt with GFPGAN v1.4 (sharper eyes, skin and hair, scratches and blur on the face removed) and blended back in. Group photos work; each face is handled separately.
- **Upscales small scans** 2x or 4x with Real-ESRGAN, which also cleans up noise and JPEG artifacts.
- **Reads almost any photo**: JPEG, PNG, TIFF (including 16-bit scans), WebP, HEIC from iPhones, BMP and GIF, with EXIF rotation applied.
- **Takes photos from anywhere**: direct links, Google Drive and Dropbox share links, web pages that declare a main image (such as archive item pages), or files you upload.
- **Saves a before/after image** if you want one for sharing.
- **Fair billing**: you pay per restored photo and per restored face. Links that fail and files that can't be read cost nothing.

### How to use it

1. Paste photo links or upload photos.
2. Keep the defaults (colorize black-and-white photos, restore faces, upscale small photos) or change them.
3. Click **Start**. Each restored photo appears in the **Output** tab with a preview and a download link.

You can also run it through the [Apify API](https://docs.apify.com/api/v2), on a schedule, or from Make, n8n, Zapier and other integrations.

### Input

| Field | What it does |
| --- | --- |
| `imageUrls` | Links to photos, Google Drive or Dropbox share links, or pages that declare a main image. |
| `files` | Photos uploaded from your computer or picked from an Apify key-value store. |
| `colorize` | `auto` (default) colorizes black-and-white and sepia photos only; `always` colorizes every photo, which can revive badly faded color prints; `never` keeps the original colors. |
| `restoreFaces` | Restore every face with GFPGAN v1.4 (default on). |
| `faceRestorationStrength` | 1.0 (default) uses the restored face as it is; lower values blend in the original face. |
| `upscale` | `auto` (default) enlarges photos up to 600 px 4x and photos up to 1200 px 2x; or choose `1x`, `2x` or `4x`. Results are capped at 4096 px on the long side. |
| `outputFormat` | `jpg` (default), `png` or `webp`. |
| `saveComparison` | Also save a side-by-side before/after image. |
| `maxPhotos` | Stop after this many photos (default 100). |

Example:

```json
{
  "imageUrls": [
    "https://tile.loc.gov/storage-services/service/pnp/fsa/8d17000/8d17400/8d17440r.jpg",
    "https://drive.google.com/file/d/YOUR_FILE_ID/view?usp=sharing"
  ],
  "upscale": "2x",
  "saveComparison": true
}
```

### Output

Each photo becomes one dataset item. The restored image is saved in the run's key-value store, and `imageUrl` is its download link:

```json
{
  "url": "https://tile.loc.gov/storage-services/service/pnp/fsa/8d17000/8d17400/8d17440r.jpg",
  "status": "ok",
  "error": null,
  "imageUrl": "https://api.apify.com/v2/key-value-stores/<store>/records/001-8d17440r.jpg?signature=...",
  "comparisonUrl": "https://api.apify.com/v2/key-value-stores/<store>/records/001-8d17440r-before-after.jpg?signature=...",
  "fileName": "001-8d17440r.jpg",
  "inputWidth": 640,
  "inputHeight": 486,
  "width": 1280,
  "height": 972,
  "scale": 2,
  "wasBlackAndWhite": true,
  "colorized": true,
  "facesFound": 2,
  "facesRestored": 2,
  "format": "jpg",
  "processingSeconds": 44.7,
  "steps": {"colorize": 12.37, "detectFaces": 0.16, "restoreFaces": 18.84, "upscale": 12.91, "pasteFaces": 0.06}
}
```

A photo that couldn't be downloaded or read gets `status: "failed"` and an `error` that says why, and isn't billed. Download your images within your plan's data retention period, or copy them to your own storage, because run storage expires.

### Pricing

You pay per event, at the prices shown on this page:

- **Photo restored**: once per photo that was restored and saved.
- **Face restored**: once per face restored. A portrait usually has one face and a family photo several. Turn off `restoreFaces` if you only want colorization or upscaling.

Links that fail and files that can't be read are never charged. If you set a maximum cost per run, the Actor stops when the next photo wouldn't fit, and restores the biggest faces first when the budget can't cover them all.

### Speed

A typical photo takes 30 to 60 seconds with the default 4 GB of memory, after about 20 seconds to start the run. The example photo above (two faces, enlarged 2x) took 45 seconds. Choose 8 GB for batches to make it about twice as fast; the price per photo stays the same.

### Tips and limits

- Faces need to be at least roughly visible: very small (under about 10 px between the eyes), turned-away or covered faces may not be detected and are left as they are.
- Restored faces and colors are AI reconstructions. They look natural, but details such as eye color or clothing colors are the model's best guess, not a record of the original. Don't use the results as evidence or for identification.
- Scratches, tears and stains outside faces aren't removed yet. The upscaler cleans noise and grain but not large cracks.
- Inputs above 25 megapixels are reduced to 25 megapixels first.
- Colorizing a photo that's already in color (`colorize: always`) replaces its colors, which helps with badly faded prints but loses any color that was still right.

### For AI agents and developers

This Actor works with the [Apify MCP server](https://mcp.apify.com), so AI agents can call it as a tool: pass `imageUrls` and read `imageUrl` from each dataset item. Every item has the same documented fields, and `status` tells you whether a photo succeeded. For a direct API call:

```bash
curl -X POST "https://api.apify.com/v2/acts/jumblemog~old-photo-restoration/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"imageUrls": ["https://example.com/old-photo.jpg"]}'
```

### Privacy

Photos are downloaded into the run, processed in memory and saved only to your own Apify storage. Nothing is sent to an outside AI service.

### Credits and licenses

- Colorization: [DDColor](https://github.com/piddnad/DDColor) by Kang et al. (ICCV 2023), Apache-2.0, ModelScope-trained weights.
- Face restoration: [GFPGAN v1.4](https://github.com/TencentARC/GFPGAN) by Tencent ARC, Apache-2.0 (the clean architecture, without the third-party CUDA code).
- Upscaling: [Real-ESRGAN](https://github.com/xinntao/Real-ESRGAN) general x4 v3 by Xintao Wang et al., BSD-3-Clause.
- Face detection: [YuNet](https://github.com/opencv/opencv_zoo/tree/main/models/face_detection_yunet), MIT.

# Actor input Schema

## `imageUrls` (type: `array`):

Direct links to photos (JPEG, PNG, TIFF, WebP, HEIC, BMP, GIF), Google Drive or Dropbox share links, or web pages that declare a main image (for example a museum or archive item page). Instagram, Facebook, X, TikTok and Pinterest links aren't supported because their terms don't allow downloading.

## `files` (type: `array`):

Upload photos from your computer, or pick files you already stored in an Apify key-value store.

## `colorize` (type: `string`):

auto: colorize black-and-white and sepia photos and leave color photos as they are. always: colorize every photo (useful for faded color photos). never: keep the original colors or tones.

## `restoreFaces` (type: `boolean`):

Find every face and restore it with GFPGAN v1.4: sharper eyes, skin and hair, with scratches and blur on the face removed. Each restored face is billed as a 'face' event.

## `faceRestorationStrength` (type: `number`):

1.0 uses the restored face as it is. Lower values blend in the original face, which keeps more of the original look if restored faces look too smooth.

## `upscale` (type: `string`):

auto: photos up to 600 px are enlarged 4x and photos up to 1200 px 2x, larger ones keep their size. Results are capped at 4096 px on the long side.

## `outputFormat` (type: `string`):

File format of the restored photos.

## `saveComparison` (type: `boolean`):

Also save a side-by-side image of the original and the restored photo, handy for sharing.

## `maxPhotos` (type: `integer`):

Stop after this many photos, so the cost of a run stays predictable.

## Actor input object example

```json
{
  "imageUrls": [
    "https://tile.loc.gov/storage-services/service/pnp/fsa/8d17000/8d17400/8d17440r.jpg"
  ],
  "colorize": "auto",
  "restoreFaces": true,
  "faceRestorationStrength": 1,
  "upscale": "auto",
  "outputFormat": "jpg",
  "saveComparison": false,
  "maxPhotos": 100
}
```

# Actor output Schema

## `photos` (type: `string`):

One item per photo: download link, size, whether it was colorized and how many faces were restored.

## `files` (type: `string`):

The restored photos (and before/after images, if requested) saved in the run's key-value store.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "imageUrls": [
        "https://tile.loc.gov/storage-services/service/pnp/fsa/8d17000/8d17400/8d17440r.jpg"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("jumblemog/old-photo-restoration").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "imageUrls": ["https://tile.loc.gov/storage-services/service/pnp/fsa/8d17000/8d17400/8d17440r.jpg"] }

# Run the Actor and wait for it to finish
run = client.actor("jumblemog/old-photo-restoration").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "imageUrls": [
    "https://tile.loc.gov/storage-services/service/pnp/fsa/8d17000/8d17400/8d17440r.jpg"
  ]
}' |
apify call jumblemog/old-photo-restoration --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jumblemog/old-photo-restoration"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ZxsnUCDEE73Fd6LyO/builds/Kf2WMt2yEfGQhJyca/openapi.json
