# Viewport Meta Validator (`zerobreak/viewport-meta-validator`) Actor

Viewport meta validator that fetches any website and checks its mobile viewport tag for missing settings, fixed widths, and zoom-blocking restrictions that hurt Google rankings.

- **URL**: https://apify.com/zerobreak/viewport-meta-validator.md
- **Developed by:** [ZeroBreak](https://apify.com/zerobreak) (community)
- **Categories:** SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.99/month + usage

To use this Actor, you pay a monthly rental fee to the developer. The rent is subtracted from your prepaid usage every month after the free trial period.You also pay for the Apify platform usage, which gets cheaper the higher Apify subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#rental-actors

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Viewport Meta Validator: Check Mobile Viewport Tags Across Any Website

Viewport Meta Validator checks any list of URLs for correct `<meta name="viewport">` configuration. A missing or broken viewport tag is one of the most common reasons websites fail Google's mobile-friendliness test, which feeds directly into mobile search rankings.

### Use cases

- **SEO audits**: scan full URL lists for missing or broken viewport tags before a ranking review
- **Site migrations**: confirm viewport tags survived a CMS switch or template change
- **Quality assurance**: catch viewport problems in staging before going live
- **Agency reporting**: export structured viewport data for client SEO reports
- **Monitoring**: run on a schedule to catch regressions after code deploys

### Input

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `url` | string | none | Single URL to check. Include the full URL with protocol. |
| `urls` | array | none | List of URLs to check, one per line. Combined with `url` if both are provided. |
| `maxUrls` | integer | 100 | Cap on how many URLs to process per run. Hard maximum is 1000. |
| `requestTimeoutSecs` | integer | 30 | How long to wait for each page before timing out. |
| `proxyConfiguration` | object | Datacenter (Anywhere) | Proxy type and location for requests. Supports Datacenter, Residential, Special, and custom proxies. Optional. |

#### Example input

```json
{
    "urls": [
        "https://apify.com",
        "https://news.ycombinator.com"
    ],
    "maxUrls": 50,
    "proxyConfiguration": { "useApifyProxy": true }
}
```

### What data does this actor extract?

Each URL produces one record:

```json
{
    "url": "https://apify.com",
    "statusCode": 200,
    "hasViewportMeta": true,
    "viewportCount": 1,
    "viewportContent": "width=device-width, initial-scale=1",
    "directives": { "width": "device-width", "initial-scale": "1" },
    "isValid": true,
    "isMobileFriendly": true,
    "issues": [],
    "recommendations": [],
    "checkedAt": "2025-01-15T10:30:00.000Z",
    "error": null
}
```

| Field | Type | Description |
|-------|------|-------------|
| `url` | string | Final URL after redirects |
| `statusCode` | integer | HTTP response code |
| `hasViewportMeta` | boolean | Whether the page has a viewport meta tag |
| `viewportCount` | integer | Number of viewport tags found (should be 1) |
| `viewportContent` | string | Raw content attribute value |
| `directives` | object | Parsed viewport properties as key-value pairs |
| `isValid` | boolean | Passes all best-practice checks |
| `isMobileFriendly` | boolean | Meets Google mobile-friendliness requirements |
| `issues` | array | Problems found with the viewport tag |
| `recommendations` | array | Suggested fixes for each issue |
| `checkedAt` | string | ISO 8601 timestamp |
| `error` | string | Error message if the page could not be fetched |

### What gets checked

The validator runs each viewport tag through six rules:

1. **Tag presence**: pages with no viewport tag at all get flagged immediately
2. **width=device-width**: fixed-width values like `width=320` break responsive layouts on modern screens
3. **initial-scale=1**: values other than 1 cause inconsistent zoom behavior on first load
4. **user-scalable=no**: blocks pinch-to-zoom, an accessibility violation Google penalizes in mobile rankings
5. **maximum-scale restrictions**: values below 2 prevent users from zooming in at all
6. **Duplicate tags**: multiple viewport tags cause unpredictable browser behavior; only the first one is used

### How it works

1. Accepts one URL or a list via the `url` and `urls` inputs
2. Fetches each page with a realistic browser User-Agent and optional proxy support
3. Parses the HTML and locates all `<meta name="viewport">` tags
4. Extracts and parses the `content` attribute into individual directives
5. Runs each directive through the validation rules above
6. Pushes one structured record per URL to the dataset

### Integrations

Connect Viewport Meta Validator with other tools using [Apify integrations](https://apify.com/integrations). Export results to Google Sheets for client reports, trigger Slack alerts when issues are found, or chain it with a URL scraper to validate your full site in one workflow. You can also use [webhooks](https://docs.apify.com/integrations/webhooks) to trigger downstream tasks when results land.

### FAQ

**Does this actor work on JavaScript-rendered pages?**
It fetches raw HTML, which covers most real-world cases. Viewport tags live in the static `<head>` on the vast majority of sites. For heavy single-page apps that inject meta tags via JavaScript, a browser-based approach would be needed.

**How many URLs can it process per run?**
Up to 1000 (set with `maxUrls`). For bigger crawls, split your list across multiple runs or feed URLs in from an Apify dataset.

**What does a passing viewport tag look like?**
The minimum is `<meta name="viewport" content="width=device-width, initial-scale=1">`. Missing either of those two properties will trigger an issue.

**Why does user-scalable=no matter for SEO?**
Google's mobile crawler reads the viewport tag when assessing mobile-friendliness. Pages that block zoom get flagged by Lighthouse and can lose ground in mobile search. It's one of the easier fixes with real ranking impact.

**Can I run this on a schedule?**
Yes. Set up a scheduled run in Apify Console and point it at your URL list. Any new issues that appear between runs show up in the dataset for comparison.

### Start checking viewport tags

Run Viewport Meta Validator on your URL list and export the results straight to a spreadsheet or drop them into your SEO reporting workflow.

# Actor input Schema

## `url` (type: `string`):

Single URL to check for viewport meta tag configuration. Include the full URL with protocol (https://). Combined with 'URLs' if both are provided.

## `urls` (type: `array`):

List of URLs to check. One URL per line. Combined with 'URL' if both are provided.

## `maxUrls` (type: `integer`):

Maximum number of URLs to process per run. Caps costs on large lists. Hard maximum is 1000.

## `requestTimeoutSecs` (type: `integer`):

How long to wait for each page to respond before timing out.

## `proxyConfiguration` (type: `object`):

Select proxies to use for requests. Helps avoid IP blocking and rate limits. Datacenter proxies are fastest; Residential proxies are harder to detect.

## Actor input object example

```json
{
  "url": "https://apify.com",
  "urls": [
    "https://apify.com",
    "https://news.ycombinator.com"
  ],
  "maxUrls": 100,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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 = {
    "url": "https://apify.com",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("zerobreak/viewport-meta-validator").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 = {
    "url": "https://apify.com",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("zerobreak/viewport-meta-validator").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "url": "https://apify.com",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call zerobreak/viewport-meta-validator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=zerobreak/viewport-meta-validator",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

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