# Website to Markdown Converter — Firecrawl Alternative (`khadinakbar/firecrawl-alternative`) Actor

Convert public websites to clean Markdown with a bounded crawl. Export one record per HTML page with requested and final URLs, title, canonical link, observed links, and timestamps for search or knowledge workflows.

- **URL**: https://apify.com/khadinakbar/firecrawl-alternative.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Developer tools, SEO tools, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 markdown page extracteds

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?

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

## Website to Markdown Converter — Firecrawl Alternative

Convert public websites to clean Markdown with a bounded crawl. Export one record per HTML page with requested and final URLs, title, canonical link, observed links, and timestamps for search or knowledge workflows. For knowledge teams, each dataset record is one crawled HTML page converted to Markdown with its source context intact.

### Workflow: put the results to work

Start with a public documentation or help-center URL and a small page cap. Review the Markdown and source links before scaling the crawl or loading pages into a knowledge system. Set selectors and scope to exclude navigation or sections that do not belong in the destination.

### Scope

- Logging in, bypassing access controls, interacting with a browser, extracting protected content, or crawling private networks.
- Web search, search-result scraping, AI/LLM JSON extraction, change monitoring, screenshots, files/PDFs, cached-content controls, or a hosted browser session.
- A claim that this replaces Firecrawl's full product. It replaces only the bounded public HTML-to-Markdown crawl described here.

Firecrawl is a trademark of its owner. This independent Actor is not affiliated with, associated with, or endorsed by Firecrawl.

### What a page record contains

| Field | Meaning |
| --- | --- |
| `markdown` | Clean Markdown converted from public HTML after scripts, styles, frames, and optional selectors are removed. |
| `sourceUrl` / `finalUrl` | The requested URL and public URL reached after ordinary redirects. |
| `title` / `canonicalUrl` | Observed HTML title and canonical link, if present. |
| `links` / `linkCount` | Up to 250 observed HTTP(S) links and the pre-truncation unique count. |
| `collectedAt` / `provenance` | Collection timestamp and the fixed `public_html_response` provenance label. |
| `limitations` / `warnings` | Explicit processing boundary and non-fatal page warnings. |

### Input

Start with a small page limit. Supply at least one public HTTP(S) URL; private, localhost, credentialed, and non-HTTP URLs are rejected. `same-hostname` follows only the exact host; `same-domain` can include subdomains; `page-only` processes only the supplied starts.

```json
{
  "startUrls": ["https://example.com/docs"],
  "crawlScope": "same-hostname",
  "maxPages": 10,
  "maxDepth": 2,
  "removeSelectors": ["nav", "footer"],
  "respectRobotsTxt": true,
  "maxConcurrency": 2
}
```

`maxPages` is a hard budget from 1 to 200. If eligible pages remain when that budget is reached, the terminal result is `PARTIAL` rather than a claim of full-site coverage. `maxDepth: 0` processes only start URLs. Keep `respectRobotsTxt` enabled unless you have clear authority to crawl beyond the public robots policy.

### Output example

```json
{
  "sourceUrl": "https://example.com/docs",
  "finalUrl": "https://example.com/docs/",
  "canonicalUrl": "https://example.com/docs/",
  "statusCode": 200,
  "contentType": "text/html; charset=utf-8",
  "title": "Example documentation",
  "markdown": "# Example documentation\n\nHelpful public content.",
  "cleanedHtml": null,
  "links": ["https://example.com/docs/start"],
  "linkCount": 1,
  "collectedAt": "2026-09-07T00:00:00.000Z",
  "provenance": "public_html_response",
  "limitations": "HTTP HTML crawl only; may miss JavaScript-rendered, authenticated, blocked, non-HTML, browser-interaction, AI-extracted, search-discovered, monitored, or cached content.",
  "warnings": []
}
```

Each terminal run also writes `OUTPUT` and `RUN_SUMMARY` in the default key-value store. Outcomes are `COMPLETE`, `PARTIAL`, `VALID_EMPTY`, `INVALID_INPUT`, `UPSTREAM_FAILED`, or `CONFIG_ERROR`. A valid empty result and an input error succeed with useful diagnostics; an upstream failure with no saved pages fails honestly after those records are written.

### API and agent use

Use the Actor through Apify Console, API, schedules, or an approved Apify MCP integration. Replace the input below with a public site you are authorized to crawl.

```bash
apify call khadinakbar/firecrawl-alternative --input='{
  "startUrls": ["https://example.com/docs"],
  "crawlScope":"same-hostname",
  "maxPages":10,
  "maxDepth":2
}'
```

```bash
curl -X POST "https://api.apify.com/v2/acts/khadinakbar~firecrawl-alternative/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"startUrls":["https://example.com/docs"],"crawlScope":"same-hostname","maxPages":10,"maxDepth":2}'
```

> AI agent prompt: Crawl this authorized public documentation URL, stay on the same hostname, stop after ten pages or two link hops, and return source-linked Markdown. Read the `OUTPUT` outcome and dataset before using the content; preserve source URLs, collection time, scope, and run cost in the downstream workflow.

### Firecrawl comparison for bounded Markdown crawling

The comparable job is narrow: collect up to a bounded number of caller-supplied public HTML pages and convert each one to clean Markdown with provenance. Firecrawl documents a broader API with crawl, scrape, map, search, browser/interact, and agentic capabilities. Choose Firecrawl when you need those hosted capabilities, AI extraction, search discovery, monitoring, cache/retention controls, parsing, or browser work. Choose this Actor when the bounded public HTML crawl and an Apify dataset/API/scheduling workflow are the actual job.

| Decision dimension | This Actor | Firecrawl |
| --- | --- | --- |
| Scope and workflow | Bounded public HTML-to-Markdown crawl from caller-supplied URLs. | Broader web-data API capabilities are documented. |
| Billing and same-job cost | Pay per event plus platform usage; see the Pricing tab for current rates. | Uses listed credits per crawl page and plan-based billing. |
| Effective efficiency | A final benchmark is pending; page caps make the requested volume explicit. | A final same-job benchmark is pending. |
| Output and provenance | Per-page Markdown with source/final/canonical URLs, links, and collection time. | Multiple output formats are documented. |
| Integrations and automation | Apify dataset, API, schedules, webhooks, and an approved MCP workflow where the caller's client supports it. | Its own API and MCP integrations are documented. |
| Recommended boundary | A focused public HTML crawl workflow. | Browser, search, extraction, monitoring, cache, parsing, and broader suite workflows. |

The private comparison dossier records the current scope and pricing observations. This README makes no blanket parity, lower-cost, faster, or reliability claim; no equivalent final-build cloud benchmark exists yet.

### Limitations, best results, and responsible use

- Begin with an exact public documentation or help-center URL, a small `maxPages`, and `same-hostname` scope.
- Requests are direct by default. For an authorized public site that rate-limits or blocks direct traffic, choose an Apify Proxy route in the input; its platform usage is additional to the page event price.
- Remove navigation or cookie-banner content only with simple selectors, such as `nav`, `footer`, or `.cookie-banner`; invalid selectors are retained as warnings.
- Expect plain HTTP HTML extraction. JavaScript-rendered, authenticated, blocked, binary, and browser-interaction pages can yield partial or failed outcomes.
- Respect the website's terms, robots policy, intellectual-property rights, privacy commitments, rate limits, and applicable law. Crawl only sources you are authorized to access and process.

### Builder's note

I built this Actor to persist source URLs, final URLs, canonical hints, a bounded link list, and a limitation statement next to every Markdown page. A Markdown string without that context is difficult to validate, refresh, or safely reuse in a downstream knowledge workflow.

### Release status

This is a private build. It has not been published to the Apify Store and must not be described as release-ready until a final private build passes the required cloud acceptance matrix with delayed dataset, `OUTPUT`, `RUN_SUMMARY`, and charge readback.

### Pricing and run costs

This Actor uses **Pay per event plus Apify platform usage**. The [Pricing tab](https://apify.com/khadinakbar/firecrawl-alternative/pricing) lists the current event rates and billing terms.

| Event | Billing unit | When it applies |
|---|---|---|
| `apify-actor-start` | Actor Start | Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event). |
| `page-extracted` | Markdown page extracted | Charged once for each validated page saved as a source-linked Markdown document. |

Run cost combines the charged events and Apify platform usage. Review the run charge limit and requested result count before starting.

### Connect an AI agent

Use the [Apify MCP configurator](https://mcp.apify.com) to choose an available client connection. Inspect this Actor’s current input schema and required credentials before running it.

# Actor input Schema

## `startUrls` (type: `array`):

Use this to supply public HTTP(S) pages where crawling begins. Example: https://example.com/docs. The Actor returns actionable diagnostics for private, credentialed, localhost, malformed, and non-HTTP URLs. Use only websites you are authorized to crawl.

## `crawlScope` (type: `string`):

Use same-hostname to follow links only on the exact host, same-domain to include subdomains, or page-only to process just the supplied start URLs. This does not discover web-search results.

## `maxPages` (type: `integer`):

Use this hard page budget to limit the crawl. Defaults to 10 and accepts 1–200. The run becomes PARTIAL when eligible URLs remain at the cap; each saved page is a billable result.

## `maxDepth` (type: `integer`):

Use this to limit link hops from a start URL. Zero means start URLs only; defaults to 2 and accepts 0–8. It is not a site-map or search mode.

## `includeHtml` (type: `boolean`):

When enabled, each result includes cleaned HTML alongside Markdown. Default is false to keep data compact. This is not a raw-response archive or screenshot feature.

## `removeSelectors` (type: `array`):

Optional CSS selectors removed before Markdown conversion, such as nav, footer, or .cookie-banner. Use only simple selectors that apply to pages you control or are authorized to process. Invalid selectors become page warnings.

## `respectRobotsTxt` (type: `boolean`):

When enabled (default), Crawlee skips paths disallowed for this crawler. Disable only where you have authorization to crawl beyond the public robots policy.

## `maxConcurrency` (type: `integer`):

Parallel public HTTP requests. Defaults to 3 and accepts 1–10. Lower this for polite, low-impact crawling. This is HTTP concurrency, not browser-session count.

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

Optional Apify Proxy configuration for public HTTP requests. Requests are direct by default; select a proxy only for public sites where you have authorization and need a different network route. Proxy usage is additional platform usage, not a login, cookie, account credential, or custom authorization header.

## Actor input object example

```json
{
  "startUrls": [
    "https://example.com"
  ],
  "crawlScope": "same-hostname",
  "maxPages": 5,
  "maxDepth": 1,
  "includeHtml": false,
  "removeSelectors": [
    "nav",
    "footer"
  ],
  "respectRobotsTxt": true,
  "maxConcurrency": 2,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `pages` (type: `string`):

One source-linked clean Markdown document for each persisted public HTML page.

## `output` (type: `string`):

Terminal outcome, persisted count, charged events, and warnings.

## `runSummary` (type: `string`):

Detailed crawl diagnostics and configured scope/caps.

# 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 = {
    "startUrls": [
        "https://example.com"
    ],
    "crawlScope": "same-hostname",
    "maxPages": 5,
    "maxDepth": 1,
    "includeHtml": false,
    "respectRobotsTxt": true,
    "maxConcurrency": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/firecrawl-alternative").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 = {
    "startUrls": ["https://example.com"],
    "crawlScope": "same-hostname",
    "maxPages": 5,
    "maxDepth": 1,
    "includeHtml": False,
    "respectRobotsTxt": True,
    "maxConcurrency": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/firecrawl-alternative").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 '{
  "startUrls": [
    "https://example.com"
  ],
  "crawlScope": "same-hostname",
  "maxPages": 5,
  "maxDepth": 1,
  "includeHtml": false,
  "respectRobotsTxt": true,
  "maxConcurrency": 2
}' |
apify call khadinakbar/firecrawl-alternative --silent --output-dataset

```

## MCP server setup

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

```

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/ALKZ2E8O8oytU3RGs/builds/dlgMmeNQ9LJh8m4Ur/openapi.json
