# Morningstar Scraper \[$1💰/1K] | Quotes | Holdings | Ratings (`ahmed_jasarevic/morningstar-scraper`) Actor

Pull Morningstar quotes, live prices, fund holdings, star and analyst ratings, performance tables, profiles, market news and movers — seven resources, each in its own dataset, no API key and no browser. Built for advisors, fintech apps and investment research. From $1 per 1,000 quotes.

- **URL**: https://apify.com/ahmed_jasarevic/morningstar-scraper.md
- **Developed by:** [Ahmed Jasarevic](https://apify.com/ahmed_jasarevic) (community)
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 1,000 qoutes & live prices

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Morningstar Scraper

Extract Morningstar quotes, live prices, fund holdings, star and analyst ratings, performance tables, profiles, market news and market movers — seven resources, each writing to its own dataset — without a browser or an API key, from $1 per 1,000 quotes.

**Built for:**

- Investment advisors and wealth managers maintaining client research
- Fintech apps that need structured quotes, ratings and holdings
- Monitoring a watchlist of funds, ETFs and stocks
- Building a joinable fund database (holdings, ratings, performance)
- Asset managers tracking category performance and analyst views

### Get Morningstar Quotes, Ratings & Fund Holdings Without an API Key

Give the actor tickers (`VFIAX`, `VOO`, `AAPL`), fund names, ISINs or Morningstar quote URLs — each is resolved through Morningstar's own security-search endpoint — then select the resources you need. Every resource writes to its own dataset (`quotes`, `holdings`, `ratings`, `performance`, `profile`, `news`, `movers`, plus a `securities` resolution log), rows carry `secId` so datasets join cleanly, and only selected resources generate requests and charges. A default run with the three prefilled securities and all resources produces about 132 rows across the eight datasets.

### How It Works

![How the Morningstar Scraper works: securities resolve to secIds, then seven JSON resources produce quotes, holdings, ratings and profiles.](https://api.apify.com/v2/key-value-stores/oeuA0kLOyhbRM4fzt/records/how-it-works-morningstar-scraper)

Rather than render pages behind Morningstar's AWS WAF, the Actor calls the same JSON services the site uses: the public SAL API, Nuxt front-end stores, an Arc RSS feed and open sitemaps. A shared secId links every resource.

Seven datasets cover quotes, holdings, star and analyst ratings, performance, profiles, news and daily movers, with only the selected resources billed.

Morningstar's HTML pages sit behind an AWS WAF challenge that turns away plain HTTP clients, so this actor skips page rendering entirely and calls the JSON surfaces the site's own front end uses:

1. **SAL public service** (`api-global.morningstar.com`, authenticated only with the public `apikey` header the site embeds) — quote metrics, holdings, star/analyst ratings, performance table, style box, risk, profile.
2. **Nuxt front-end stores** (`www.morningstar.com/api/v2/stores/...`) — ticker/name/ISIN → security-ID resolution, live price/NAV, daily movers.
3. **Arc RSS feed** (`media.morningstar.com`) — market news.
4. **Sitemaps** (open) — quote-URL enumeration for bulk seeding.

The endpoints were found in the site's own JS bundles; all answer with clean JSON, so the actor runs as a pure HTTP crawler on 256 MB of memory — no Playwright, no browser. Analyst-research pages, price-target and screener stores are login-gated (401) and are not read.

### Input Parameters

| Field | Type | Required | Default | Notes |
| --- | --- | --- | --- | --- |
| `securities` | array | No\* | `[]` | Tickers (`VFIAX`, `VOO`, `AAPL`), fund names, ISINs or full Morningstar quote URLs. |
| `resources` | array | No | all seven | Any subset of `quotes`, `holdings`, `ratings`, `performance`, `profile`, `news`, `movers`. |
| `maxSecurities` | integer | No | `25` | Securities per run; free accounts are capped at 10. |
| `maxHoldingsPerFund` | integer | No | `25` | Portfolio positions saved per fund. |
| `maxNewsItems` | integer | No | `25` | Market-news items from the RSS feed. |
| `maxRequestsPerCrawl` | integer | No | `500` | Hard cap on HTTP requests (25 securities with all resources ≈ 252 requests). |
| `proxy` | object | No | disabled | Standard Apify proxy picker; enable if your IPs get WAF-challenged. |

\* Provide at least one security unless you only want `news` / `movers` (then deselect all per-security resources).

### Output Fields

The default dataset is intentionally empty — results go to **one dataset per resource**:

| Dataset | Rows | Key fields |
| --- | --- | --- |
| `securities` | 1 per input | `securityID`, `performanceID`, `ticker`, `name`, `exchange`, `slug`, `investmentType`, `isin`, `resolve_error` |
| `quotes` | 1–2 per security | SAL quote metrics (expense ratio, yield, fund size, style box, benchmark…) + live `price`/NAV |
| `holdings` | up to `maxHoldingsPerFund` per fund | position weight, market value, sector, moat, forward P/E, per-holding ratings; parent `secId` |
| `ratings` | 1 per security | star ratings (3/5/10Y), analyst Medalist rating with people/process/price/parent scores, rating history |
| `performance` | 1 per security | annual returns vs category and index |
| `profile` | up to 4 per security | `meta`, `profile`, `style`, `risk` rows (ISIN, category, domicile, style box, risk/return) |
| `news` | up to `maxNewsItems` | title, link, author, description, date |
| `movers` | up to 30 per run | daily gainers / losers / most active with quote snapshot |

### Example Input

```json
{
  "securities": ["VFIAX", "VOO", "AAPL"],
  "resources": ["quotes", "holdings", "ratings"],
  "maxSecurities": 10,
  "maxHoldingsPerFund": 25
}
```

### Example Output

```json
{
  "itemType": "price",
  "secId": "0P000000GY",
  "name": "Apple Inc",
  "ticker": "AAPL",
  "lastPrice": 247.12,
  "change": 1.34,
  "changePercent": 0.54,
  "asOfSource": "www.morningstar.com realtime store"
}
```

### Automate Portfolio & Market Monitoring With Schedules & Webhooks

- **Daily watchlist prices:** schedule `resources: ["quotes"]` for your tickers and load the delta into a dashboard; the realtime store row (`itemType: "price"`) carries the live value.
- **Quarterly holdings rotation:** run `holdings` after each fund reports and diff positions by `secId` + security name.
- **Daily news & movers:** schedule `news` / `movers` alone — no securities are resolved, so the run stays small and cheap.
- Dataset webhooks push finished runs to Slack, email or a warehouse; recurring runs also improve this actor's Store recommendation signals.

### Related Actors

- [Yahoo Finance Scraper - Stocks, Fundamentals & News](https://apify.com/benthepythondev/yahoo-finance-scraper) — the largest stock-data actor in this cluster, closest everyday alternative.
- [Yahoo Finance Scraper — Quotes, Fundamentals, Options & News](https://apify.com/memo23/yahoo-finance-scraper) — Yahoo Finance coverage with options data.
- [Morningstar Fund & ETF Scraper](https://apify.com/parseforge/morningstar-scraper) — Morningstar fund-list collection with category filters.
- [ETF Holdings Tracker — Daily Constituents & Weights API](https://apify.com/nexgendata/etf-holdings-tracker) — ETF constituents and weights tracking.
- [Morningstar Quote Scraper](https://apify.com/moving_beacon-owner1/morningstar-quote-scraper) — lightweight Morningstar quotes.

### Frequently Asked Questions

#### Why use this actor instead of the official API?

Morningstar's official developer offering (developer.morningstar.com — Direct Web Services REST APIs and an MCP server) is a contracted, enterprise product: OAuth 2.0 credentials, onboarding through a Morningstar account manager, and a Market Data API whose credentials are IP-restricted. This actor instead reads the public JSON endpoints the morningstar.com front end itself calls — no contract, no OAuth, no IP allowlist — and packages seven resources (quotes, holdings, ratings, performance, profile, news, movers) as separate datasets with Apify's export, scheduling and webhook tooling on top.

#### Is there a free Morningstar API?

Not really. The official API requires a business agreement, and the free website is for human browsing (its HTML sits behind a WAF challenge). This actor is the keyless middle path: public JSON surfaces, pay-per-event pricing from $1 per 1,000 quotes, and a capped free preview on free accounts.

#### How do I get fund holdings data?

Select the `holdings` resource — you get up to `maxHoldingsPerFund` positions per fund with weight, market value, sector, forward P/E and per-holding ratings, joined to the parent fund via `secId`. (If you only need regulatory quarterly holdings, SEC N-PORT filings are an alternative source with a reporting lag.)

#### Does it work for ETFs and individual stocks?

Yes. Quotes, ratings, performance and profile work for stocks and ETFs too (`AAPL` resolves normally); `holdings` applies to funds. `news` and `movers` are global market resources that run once per run regardless.

#### What are the analyst ratings included?

Star ratings (3/5/10-year and overall) plus Morningstar's own analyst Medalist rating with people/process/price/parent scores and rating history — all from public SAL endpoints. Full analyst-report pages are login-gated and are not scraped.

#### Do I need an API key or account?

No key, no login. Free Apify accounts get a capped preview (10 securities, 10 holdings per fund, 10 news items); paying accounts get the full configured caps.

### For AI Agents & LLM Apps

**Purpose:** returns Morningstar quotes, holdings, ratings, performance, profile, news and movers for given tickers/names/ISINs/quote URLs — one dataset per resource, keyless, no browser.

**Minimal input:**

```json
{ "securities": ["VFIAX", "AAPL"] }
```

**Quotes-only variant:**

```json
{ "securities": ["VOO"], "resources": ["quotes"], "maxSecurities": 5 }
```

**Output fields:** (securities) securityID, performanceID, ticker, name, exchange, slug, investmentType, isin, resolve_error; (quotes) secId, name, ticker, lastPrice, change, changePercent, asOfSource; (holdings) secId, position weight, market value, sector, forward P/E; (ratings) star ratings, medalist rating, rating history; (performance) annual returns; (profile) meta/profile/style/risk rows; (news) title, link, author, date; (movers) symbol, price, daily change.

**Behaviors an agent should know:**

- The **default dataset is empty by design** — read the per-resource datasets (named by the `resources` entry), not `defaultDatasetId`.
- `resources` defaults to all seven; deselecting a resource removes both its requests and its charges. `news` and `movers` are fetched once per run (no securities needed for them).
- Free accounts are capped at 10 securities / 10 holdings per fund / 10 news items regardless of input.
- Rows join across datasets on `secId`; the `securities` dataset records resolution failures in `resolve_error`.
- `maxRequestsPerCrawl` (default 500) is the hard stop for runaway inputs; keep concurrency at default (3) to avoid WAF challenges.

**Billing:** pay-per-event — `quotes` $0.001/security, `holdings` $0.003/fund, `ratings` $0.001, `performance` $0.001, `profile` $0.002/security, `news` $0.005/run, `movers` $0.005/run, plus a run-start event; minimum total charge $0.05 per run.

### Legal & Compliance Disclaimer

This actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Morningstar, Inc. It reads only publicly reachable JSON endpoints (including the site's own embedded public API key), the public Arc RSS feed and open sitemaps — no login, no account session, no CAPTCHA solving; login-gated analyst pages and screener stores are explicitly not read. Investment data is provided as published at scrape time; users are responsible for their own compliance with Morningstar's Terms of Service and applicable law when storing, redistributing or automating access to the collected data, and nothing here is investment advice.

### SEO Keywords

morningstar api, morningstar scraper, morningstar api alternative, morningstar quotes api, fund holdings data, etf holdings api, mutual fund data api, star ratings api, analyst ratings data, fund performance data, stock quotes scraper, morningstar data, morningstar without api key, fund screener data, market movers data, investment research data, portfolio holdings database, morningstar direct web services, fund facts api, nav price data, morningstar holdings download, financial data api

# Actor input Schema

## `securities` (type: `array`):

What to scrape. Each entry can be a ticker (VFIAX, VOO, AAPL), a fund/stock name, an ISIN, or a Morningstar quote URL such as https://www.morningstar.com/funds/xnas/isqax/quote — resolved through Morningstar's own security-search store.

## `resources` (type: `array`):

Which data to pull. Each selected resource writes to its own dataset and is charged as a pay-per-event event with the same name. 'news' and 'movers' are global market data (requested once per run).

## `maxSecurities` (type: `integer`):

Maximum number of securities to process in one run (free accounts are capped at 10).

## `maxHoldingsPerFund` (type: `integer`):

Cap the number of portfolio positions saved per fund. Lower values reduce run time and cost.

## `maxNewsItems` (type: `integer`):

Maximum market-news items from the Morningstar RSS feed.

## `maxRequestsPerCrawl` (type: `integer`):

Hard cap on total HTTP requests for the run. 25 securities with all resources need about 252 requests, so the 500 default leaves headroom.

## `proxy` (type: `object`):

Select proxies to be used by your crawler.

## Actor input object example

```json
{
  "securities": [
    "VFIAX",
    "VOO",
    "AAPL"
  ],
  "resources": [
    "quotes",
    "holdings",
    "ratings",
    "performance",
    "profile",
    "news",
    "movers"
  ],
  "maxSecurities": 25,
  "maxHoldingsPerFund": 25,
  "maxNewsItems": 25,
  "maxRequestsPerCrawl": 500,
  "proxy": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `securities` (type: `string`):

Resolved Morningstar security IDs for each input ticker, name, ISIN, or quote URL.

## `quotes` (type: `string`):

SAL quote metrics and live realtime price/NAV per security.

## `holdings` (type: `string`):

Portfolio positions, capped by maxHoldingsPerFund.

## `ratings` (type: `string`):

Star ratings, analyst Medalist rating, scores, and rating history.

## `performance` (type: `string`):

Annual returns table versus category and index.

## `profile` (type: `string`):

Identifiers, firm/AUM/flows, style box, and risk summary.

## `news` (type: `string`):

Market news from the Morningstar Arc RSS feed.

## `movers` (type: `string`):

Daily gainers, losers, and most active securities.

## `summary` (type: `string`):

Run configuration, caps, and exact item counts per dataset.

# 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 = {
    "securities": [
        "VFIAX",
        "VOO",
        "AAPL"
    ],
    "proxy": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahmed_jasarevic/morningstar-scraper").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 = {
    "securities": [
        "VFIAX",
        "VOO",
        "AAPL",
    ],
    "proxy": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("ahmed_jasarevic/morningstar-scraper").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 '{
  "securities": [
    "VFIAX",
    "VOO",
    "AAPL"
  ],
  "proxy": {
    "useApifyProxy": false
  }
}' |
apify call ahmed_jasarevic/morningstar-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ahmed_jasarevic/morningstar-scraper"
        }
    }
}
```

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/7GhwB1PhUHZyi1Hk5/builds/ttmfU2wN8UTRzVSuH/openapi.json
