# DWG & DXF Extractor: CAD Text, Layers, Dimensions, Title Blocks (`bossless/dwg-dxf-extractor`) Actor

Extract every text, title block field, dimension value, layer and block from DWG and DXF drawings, straight from the CAD file: exact data, not AI guesses from a picture. AutoCAD R12 to 2026 files, direct, Google Drive or Dropbox links. JSON + CSV per drawing. No AutoCAD needed. Pay per drawing.

- **URL**: https://apify.com/bossless/dwg-dxf-extractor.md
- **Developed by:** [Alexander Daskalov](https://apify.com/bossless) (community)
- **Categories:** Developer tools, Automation, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $32.00 / 1,000 drawing reads

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

## DWG & DXF Extractor: CAD Text, Layers, Dimensions & Title Blocks

**Get the data out of AutoCAD drawings without AutoCAD.** Paste links to DWG or DXF files (direct links, or Google Drive and Dropbox file links) and get, for every drawing:

- 🏷️ **Title block fields** as clean `TAG: value` pairs: drawing number, title, project, scale, date, drawn by, revision…
- 📝 **Every text**: TEXT, MTEXT, block attributes, attribute definitions, multileaders and table text, each with its layer and where it sits (model space, a layout or a block).
- 📏 **Dimensions with their real values**: the measured value from the geometry, the text the drawing shows, and any text override.
- 🗂️ **Layers** with color, on/off, frozen and locked state, linetype and how many entities each one holds.
- 🧩 **Blocks** with how many times each is inserted (count doors, windows, fixtures, symbols).
- 📐 **Drawing info**: AutoCAD version, units (millimeters, meters, inches…), metric or imperial, created and last-saved dates, extents and entity counts.

The data comes straight from the CAD file, so it's exact: no OCR, no AI guessing from a picture of the plan. Each drawing gives one dataset record, plus a **full JSON file** and a **texts CSV** you can open in Excel.

No AutoCAD, no API key, no account to connect.

### What can you do with it?

- **Drawing registers and document control:** pull drawing number, title, revision and date from the title blocks of a whole project folder into one table.
- **Search and index CAD archives:** make thousands of old DWG and DXF files searchable by their text, layer names and block names.
- **Quantity take-off:** count block inserts (doors, windows, sockets, fixtures) and read dimension values without opening each file.
- **Drawing QA and CAD standards checks:** check layer names, frozen or locked layers and title-block fields against your company standard.
- **Translation of drawings:** export every text to CSV, translate it, and know exactly which layer and layout each string came from.
- **Feed AI agents and RAG pipelines:** give your assistant the real text and dimensions of a drawing as JSON instead of a screenshot.
- **Migrate CAD data into BIM, ERP or PLM systems:** title-block attributes and part labels as structured data.

### What files does it accept?

| File | Versions |
|---|---|
| **DXF**, text (ASCII) or binary | Any version, from AutoCAD R12 and older to the latest |
| **DWG** | AutoCAD R11/R12, R13, R14, 2000, 2004, 2007, 2010, 2013 and 2018 file formats. AutoCAD 2019 to 2026 still save drawings in the 2018 format, so their files work too |

The file type is detected from the file's content, not its name, so a link doesn't need to end in `.dwg` or `.dxf`. Google Drive and Dropbox links must be shared as "Anyone with the link"; folders and pages that need a login don't work. A file that isn't a drawing, or a DWG in an unsupported version, gets a record explaining why and is not charged.

### How much does it cost?

Pay per drawing. No monthly fee.

| Event | Price (FREE/BRONZE) | Lower on paid plans |
|---|---|---|
| Drawing read (texts, title block, dimensions, layers and blocks, with JSON and CSV files) | **$0.04** / drawing | down to $0.032 |
| Actor start | $0.00005 / run | — |

1,000 drawings cost **$40**. You pay only for drawings actually read and saved. Nothing is charged for a broken link, a file that isn't a drawing, or a drawing that can't be read.

**Cap your spend:** set a **maximum cost per run**. When the budget runs out, no more files are started, and the run's status says so.

### How to extract data from DWG and DXF files

1. Click **Try for free**. The example input reads two sample drawings: a floor plan DXF with a title block, and a DWG full of dimensions.
2. Paste your own links into **DWG or DXF links**, one per line (up to 500 per run).
3. Optional: switch off **Include text inside block definitions**, or change **Max texts in the dataset record**.
4. Run, then open the **Drawings** view, or download each drawing's full JSON and texts CSV from the links in the record.

#### Input example

```json
{
  "fileUrls": [
    "https://api.apify.com/v2/key-value-stores/T5HtoeQYut1ufwkKC/records/sample-floor-plan.dxf",
    "https://api.apify.com/v2/key-value-stores/T5HtoeQYut1ufwkKC/records/sample-dimensions.dwg"
  ],
  "includeBlockDefinitions": true,
  "maxTextsInRecord": 1000
}
```

| Option | Default | What it does |
|---|---|---|
| **DWG or DXF links** (`fileUrls`) | the two samples | Direct links, or Google Drive / Dropbox file links. Up to 500 per run |
| **Include text inside block definitions** (`includeBlockDefinitions`) | on | Also read the text inside block definitions: symbols, and title-block templates with their attribute definitions. Table text is always read |
| **Max texts in the dataset record** (`maxTextsInRecord`) | 1000 | How many texts each record lists, 0 to 5,000. `textCount` always has the full number, and the JSON and CSV files always hold every text |

### Output

One record per drawing. This is the real record for the sample floor plan (`sample-floor-plan.dxf`), with the lists shortened here: the full record has all 7 layers, 17 texts, 6 dimensions and 5 blocks.

```json
{
 "fileUrl": "https://api.apify.com/v2/key-value-stores/T5HtoeQYut1ufwkKC/records/sample-floor-plan.dxf",
 "fileName": "sample-floor-plan.dxf",
 "format": "dxf",
 "cadVersion": "AC1027",
 "cadRelease": "AutoCAD 2013",
 "units": "Millimeters",
 "measurement": "metric",
 "created": "2026-10-15T22:32:18",
 "updated": "2026-10-15T22:32:18",
 "extents": null,
 "layerCount": 7,
 "layers": [
  {"name": "A-WALL", "color": 7, "trueColor": null, "on": true, "frozen": false, "locked": false, "linetype": "Continuous", "entities": 4, "entitiesInBlocks": 0},
  {"name": "A-DIMS", "color": 1, "trueColor": null, "on": true, "frozen": false, "locked": false, "linetype": "Continuous", "entities": 6, "entitiesInBlocks": 0}
 ],
 "textCount": 17,
 "texts": [
  {"type": "MTEXT", "text": "Living room\n24.5 m²", "layer": "A-ANNO", "location": "Model"},
  {"type": "ATTRIB", "tag": "PROJECT", "text": "Riverside Apartments", "layer": "TITLE", "block": "TITLEBLOCK", "location": "Layout1"},
  {"type": "TEXT", "text": "SHEET 1 OF 1", "layer": "TITLE", "location": "Layout1"}
 ],
 "textsTruncated": false,
 "titleBlock": {
  "PROJECT": "Riverside Apartments",
  "TITLE": "Ground floor plan",
  "DRAWING_NO": "A-101",
  "SCALE": "1:100",
  "DATE": "2026-10-15",
  "DRAWN_BY": "Studio Example"
 },
 "dimensionCount": 6,
 "dimensions": [
  {"type": "linear", "measurement": 12000.0, "angular": false, "textOverride": null, "displayedText": "12000", "layer": "A-DIMS", "dimstyle": "EZDXF", "location": "Model"},
  {"type": "linear", "measurement": 7000.0, "angular": false, "textOverride": null, "displayedText": "7000", "layer": "A-DIMS", "dimstyle": "EZDXF", "location": "Model"}
 ],
 "dimensionsTruncated": false,
 "blockCount": 5,
 "blocks": [
  {"name": "DOOR-900", "inserts": 4, "entities": 2, "xref": false},
  {"name": "TITLEBLOCK", "inserts": 1, "entities": 7, "xref": false}
 ],
 "entityCounts": {"DIMENSION": 6, "INSERT": 5, "MTEXT": 4, "LINE": 3, "LWPOLYLINE": 1, "TEXT": 1},
 "recovered": false,
 "warnings": [],
 "jsonUrl": "https://api.apify.com/v2/key-value-stores/<store-id>/records/sample-floor-plan-ca8e196faf.json",
 "textsCsvUrl": "https://api.apify.com/v2/key-value-stores/<store-id>/records/sample-floor-plan-ca8e196faf-texts.csv",
 "processingMs": 472,
 "error": null
}
```

The second sample, `sample-dimensions.dwg`, is an AutoCAD 2013 DWG in meters with 3 layers, 24 texts and 16 dimensions (15 linear, 1 aligned).

#### The fields

| Field | What it holds |
|---|---|
| `format` | `dxf`, `dxf-binary` or `dwg`, detected from the file's content |
| `cadVersion`, `cadRelease` | The file format code and its AutoCAD release, e.g. `AC1027` = AutoCAD 2013 (for a DWG, the DWG's own version) |
| `units`, `measurement` | Drawing units (`Millimeters`, `Meters`, `Inches`, `Unitless`…) and `metric` or `imperial` (`null` when the drawing doesn't say) |
| `created`, `updated` | Created and last-saved dates as stored in the drawing (local time of whoever saved it) |
| `extents` | `{min, max}` corners in drawing units, or `null` when the file doesn't store them |
| `titleBlock` | The fields of the attributed block with the most filled-in values, taken from a layout (paper space) first, then model space. `null` when the drawing has no attributed block |
| `texts` | Each text with `type`, `text`, `layer` and `location` (`Model`, a layout name, or a block name for text inside a block definition). Attributes also have `tag` and `block`; attribute definitions have `tag` and `prompt`. Formatting codes are removed, and `%%d`, `%%p`, `%%c` become °, ±, ⌀. Table cells report the layout their table is in. In the record, a text longer than 2,000 characters is shortened; the files keep it whole |
| `dimensions` | `type` (linear, aligned, angular, angular_3p, diameter, radius, ordinate, arc), `measurement`, `angular`, `textOverride`, `displayedText`, `layer`, `dimstyle`, `location` |
| `layers` | `name`, `color` (AutoCAD color index), `trueColor`, `on`, `frozen`, `locked`, `linetype`, `entities` (in model space and layouts) and `entitiesInBlocks` |
| `blockCount`, `blocks` | How many named blocks the drawing has, and the blocks with `inserts` (how many times placed), `entities` and `xref`, most used first |
| `entityCounts` | Entities of each type in model space and layouts |
| `recovered`, `warnings` | `recovered` is `true` when the file was damaged and read in recovery mode; `warnings` lists what was found and fixed, what the reader noticed in a file it could still read (such as duplicate handles), and DWG conversion errors that were worked around |
| `jsonUrl`, `textsCsvUrl` | Download links of the full JSON result and of every text as CSV |
| `processingMs` | Time to convert and read the drawing, without the download |
| `error` | Why a file couldn't be read or failed; `null` on success |

**`measurement` vs `displayedText`:** `measurement` is the geometric value, in drawing units (degrees for angular dimensions), measured from the dimension's points. `displayedText` is what the drawing actually shows, after its dimension style has done its work: rounding, units, prefixes and scale factors. They differ when the style scales the value. In the sample DWG, a dimension with `measurement` 3.0 (meters) shows "300", because its dimension style multiplies displayed values by 100. Use `measurement` for calculations and `displayedText` for what a person reading the plot sees. `textOverride` is set when the drafter typed their own text over the value.

**Getting the files:**

- `jsonUrl` is the full result: every text, dimension, layer and block, with nothing cut.
- `textsCsvUrl` is every text as CSV (columns type, text, layer, tag, block, location), UTF-8 so Excel shows accents, symbols and Chinese text correctly.
- Both are also in the run's **key-value store** (the **JSON and CSV files** tab in Console, or the API). If your account keeps storages private, add `?token=YOUR_TOKEN` to the links.

A file that can't be read, or fails to download, gets a record with `fileUrl`, `fileName` and `error` set and every data field `null`, and isn't charged. So the dataset has one record per link.

### How fast is it?

Measured on Apify at the default 1024 MB: a typical DXF reads in under 1 second and a typical DWG in 1.5 to 2 seconds (it's converted to DXF first; an AutoCAD 2018 DWG took 4 seconds, an R12 DWG with 69 texts 7 seconds). Five DWGs in one run took 25 seconds and $0.0020 of compute in total. A 56 MB DXF with 120,001 texts read in 117 seconds, using 610 MB of the reader's 768 MB memory limit. The download comes on top. Drawings are read one at a time.

### Limits

- Up to **500 files per run**; more links are ignored with a warning in the log.
- Per record: up to **5,000 texts** (1,000 by default, see **Max texts in the dataset record**), **1,000 dimensions**, **1,000 layers** and **500 blocks**, and texts (and a dimension's `displayedText` and `textOverride`) are shortened to 2,000 characters each. A record is kept under 8 MB (the dataset's limit is 9 MB): if a drawing would go over, fewer texts or dimensions (whichever takes more room) are listed and `textsTruncated` or `dimensionsTruncated` says so. The JSON file always keeps everything.
- **Size vs memory:** at the default 1024 MB, keep DXF files under about 60 MB and DWG files under about 15 MB (a DWG is compressed and becomes a much larger DXF). For larger drawings, run with 2048 to 4096 MB; the error message says so when memory runs out. Disk is twice the memory, which caps the download size.
- **Timeouts:** 300 seconds to download a file, 120 seconds to convert a DWG and 300 seconds to read a drawing. A file that takes longer gets an error record and isn't charged.
- If 10 files in a row can't be read, the run stops starting new ones, since the links are most likely wrong.
- Links to private networks (localhost, internal IPs) are blocked.

### Use it with AI agents (MCP)

```
https://mcp.apify.com?tools=bossless/dwg-dxf-extractor
```

Ask your assistant "what's the drawing number and scale of this DWG?" or "list every room name and dimension in this floor plan", and it runs this actor and answers from the exact data in the file.

### Use the API from code

```bash
curl -X POST "https://api.apify.com/v2/acts/bossless~dwg-dxf-extractor/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"fileUrls": ["https://api.apify.com/v2/key-value-stores/T5HtoeQYut1ufwkKC/records/sample-floor-plan.dxf"]}'
```

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")
run = client.actor("bossless/dwg-dxf-extractor").call(run_input={
    "fileUrls": [
        "https://api.apify.com/v2/key-value-stores/T5HtoeQYut1ufwkKC/records/sample-floor-plan.dxf",
        "https://api.apify.com/v2/key-value-stores/T5HtoeQYut1ufwkKC/records/sample-dimensions.dwg",
    ],
})
store = client.key_value_store(run["defaultKeyValueStoreId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    if item["error"]:
        print(item["fileUrl"], "->", item["error"])
        continue
    print(item["fileName"], item["cadRelease"], item["units"], item["titleBlock"])
    full = store.get_record(item["jsonUrl"].rsplit("/", 1)[-1])["value"]    # every text and dimension
    for d in full["dimensions"]:
        print("  ", d["type"], d["measurement"], d["displayedText"])
```

### FAQ

**Do I need AutoCAD or any CAD software?** No. The drawings are read on Apify's servers. You only need links to the files.

**Can it read scanned drawings, PDFs or images of plans?** No. It reads the data inside DWG and DXF files, which is what makes it exact. A PDF or image link gets an error record ("not a DXF or DWG file") and isn't charged.

**Why is `titleBlock` empty for my drawing?** The title block is read from block attributes. Some drawings draw their title block with plain text instead; then the values are still in `texts`, just not as `TAG: value` pairs.

**Does it read text inside blocks and external references (xrefs)?** Text in block definitions, yes (switch it off with **Include text inside block definitions**). Xrefs are listed in `blocks` with `xref: true`, but their content lives in other files, so link those files too.

**What about damaged files?** Damaged DXF files are read in recovery mode where possible, with `recovered: true` and the problems listed in `warnings`. A file that can't be read at all gets an error record and isn't charged.

**Which DWG versions work?** AutoCAD R11/R12 to the 2018 format, which AutoCAD 2019 to 2026 still use. Other versions get an error record saying which version the file is, and aren't charged.

**Are my files kept?** Files are downloaded only for the run and deleted when it ends. The results stay in your own Apify run storage. Nothing is sent anywhere else.

**Is this an official Autodesk product?** No. This is an independent tool and is not affiliated with or endorsed by Autodesk. AutoCAD is a trademark of Autodesk, Inc.

### Credits

- DWG files are converted to DXF with **GNU LibreDWG** (GPLv3), used unmodified and run as a separate program.
- Drawings are read with **ezdxf** by Manfred Moitzi (MIT licence).
- The sample DWG comes from the ezdxf documentation, © Manfred Moitzi, MIT licence. The sample floor plan DXF is synthetic, made by us for this demo.

### Related tools

- [Handwriting to Text](https://apify.com/bossless/handwriting-to-text): photos, scans and PDFs of handwritten notes, letters and forms turned into text, line by line, in any language.

# Actor input Schema

## `fileUrls` (type: `array`):

Links to DWG or DXF drawings: direct files from your website or cloud storage, or Google Drive / Dropbox file links shared as 'Anyone with the link'. One file per line, up to 500 per run. The file type is detected from its content, so the link doesn't need to end in .dwg or .dxf. Folders and pages that need a login don't work.

## `includeBlockDefinitions` (type: `boolean`):

Also read the text inside block definitions (symbols, title-block templates and their attribute definitions), not only the text placed in model space and layouts. Table contents are always read.

## `maxTextsInRecord` (type: `integer`):

How many texts each dataset record lists (0 to 5,000). textCount always gives the full number, and the drawing's JSON and texts CSV files always hold every text.

## Actor input object example

```json
{
  "fileUrls": [
    "https://api.apify.com/v2/key-value-stores/T5HtoeQYut1ufwkKC/records/sample-floor-plan.dxf",
    "https://api.apify.com/v2/key-value-stores/T5HtoeQYut1ufwkKC/records/sample-dimensions.dwg"
  ],
  "includeBlockDefinitions": true,
  "maxTextsInRecord": 1000
}
```

# Actor output Schema

## `results` (type: `string`):

No description

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

No description

# 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 = {
    "fileUrls": [
        "https://api.apify.com/v2/key-value-stores/T5HtoeQYut1ufwkKC/records/sample-floor-plan.dxf",
        "https://api.apify.com/v2/key-value-stores/T5HtoeQYut1ufwkKC/records/sample-dimensions.dwg"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("bossless/dwg-dxf-extractor").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 = { "fileUrls": [
        "https://api.apify.com/v2/key-value-stores/T5HtoeQYut1ufwkKC/records/sample-floor-plan.dxf",
        "https://api.apify.com/v2/key-value-stores/T5HtoeQYut1ufwkKC/records/sample-dimensions.dwg",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("bossless/dwg-dxf-extractor").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 '{
  "fileUrls": [
    "https://api.apify.com/v2/key-value-stores/T5HtoeQYut1ufwkKC/records/sample-floor-plan.dxf",
    "https://api.apify.com/v2/key-value-stores/T5HtoeQYut1ufwkKC/records/sample-dimensions.dwg"
  ]
}' |
apify call bossless/dwg-dxf-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,bossless/dwg-dxf-extractor"
        }
    }
}
```

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/q0cNkjFKlUaypzMuS/builds/lmhG8I54iYUxn6M8I/openapi.json
