Import from CSV or Excel
The import route with no AI and no credits: upload a spreadsheet, map the columns, and AreaCacao creates or updates your recipes in bulk.
What it is
Import from CSV or Excel turns a spreadsheet into AreaCacao recipes. You prepare the file, you decide what each column means, and the importer creates (or updates) the recipes. No AI reads the file, and no credits are used.
- Path:
https://app.areacacao.com/import-recipe, Upload new tab. - How to get there: sidebar → FORMULATION → Import recipes → Upload new tab. The card sits below the photo/PDF drop zone.
- Availability: on by default for any user with an account. No plan restriction.
How it differs from importing a photo or a PDF
| CSV / Excel | Photo or PDF | |
|---|---|---|
| How the file is read | Deterministic: your columns, your mapping | AI interprets the image |
| Credits | 0 | ~15 per image, ~25 per PDF |
| Usage limit | No usage limit (there is a technical rate limit, see below) | Bounded by your credit balance |
| Several recipes per file | Yes, as many as fit in the sheet | One per file |
| Who decides what each value means | You, in the mapping step | The AI, and you correct it afterwards |
The only place AI can get involved is optional and your choice: auto-completing ingredients that aren't in your catalog (see Ingredients that don't match the catalog).
The card and its two buttons
The card is titled "CSV or Excel (no credits)" and reads: "Import your recipes from a spreadsheet. No credits used and no usage limit. Import one or many recipes at once."
It has two buttons and one expandable block:
- Import CSV/Excel — opens the wizard.
- Download template — downloads the file straight from your browser, without hitting the server.
- Quick guide: how to prepare your file — an expandable block with the fill-in rules and the full list of valid
filling_typevalues.
If the card isn't on your screen, the feature has been switched off from infrastructure (the RECIPE_IMPORT_CSV_ENABLED flag). It is on by default: it only goes off when the flag is explicitly set to false.
The template
Download template saves a file to your machine. It is a CSV with a UTF-8 BOM (so Excel keeps accented characters) containing the canonical header row plus three example recipes, picked to teach the three patterns the importer understands:
- Ganache de maracuyá — a simple filling: four rows share the same
recipe_name, and the last one carries the steps. - Trufa clásica de cacao — a filling with layers: the
partcolumn separates "Interior" from "Rebozado". - Tableta 70% cacao — a chocolate recipe: it uses
chocolate_typeandcocoa_percentand leavesfilling_typeempty.
The downloaded file is named plantilla-recetas-areacacao.csv in both languages — the filename comes from a constant in the code, not from the interface language. The column names inside are the same in both languages too.
You are not required to use the template: you can import your own sheet with your own headers and tell the wizard what each column is.
Columns
The template ships 16 columns, in this order:
recipe_name, recipe_type, chocolate_type, filling_type, cocoa_percent, part, ingredient_code, ingredient_name, quantity, unit, weight_g, cost_per_unit, cost_currency, is_supply, supply_code, steps
The wizard can map 18 fields: the 16 above plus recipe_id (Recipe ID) and cost_unit (Cost unit), which exist as mapping targets even though the template doesn't include them.
| Field | Label in the wizard | What it does |
|---|---|---|
recipe_name | Recipe name | The only required field. It groups rows: several rows with the same name make up a single recipe. |
recipe_id | Recipe ID | Updates an existing recipe instead of creating a new one. |
recipe_type | Recipe type | Accepted values: chocolate, filling, relleno. Anything else (or empty) is treated as generic. |
chocolate_type | Chocolate type | Chocolate recipes only. |
filling_type | Filling type | The filling's technical type; it enables range-based validation. |
cocoa_percent | Cocoa % | The recipe's cocoa percentage. |
part | Part / section | Separates layers or sections within the same recipe. |
ingredient_code | Ingredient code | Links the row to an exact record in your catalog. |
ingredient_name | Ingredient name | Used to look the ingredient up by name when there's no code. |
quantity | Quantity | The ingredient's quantity. |
unit | Unit | The unit the quantity is expressed in. |
weight_g | Weight (g) | Weight in grams. If left empty, it is converted from quantity + unit. |
cost_per_unit | Cost per unit | The line's unit cost. |
cost_unit | Cost unit | The unit the cost refers to. |
cost_currency | Currency | The cost's currency. |
is_supply | Is supply | Marks the row as a supply (non-edible material). |
supply_code | Supply code | Links the row to a supply in your catalog, by code. |
steps | Steps / preparation | Every step in one single cell, separated by the vertical-bar character. |
How rows are grouped
Rows are grouped by normalized recipe_name: lowercased, accents stripped, internal whitespace collapsed. So "Ganache de Maracuyá" and "ganache de maracuya" end up in the same recipe.
Fill-in rules the importer enforces
- One ingredient per row. Don't put the whole ingredient list in a single cell — the importer can't split it.
- Steps separated by
|. Fillingstepsin any one row of the recipe is enough. - Layers via
part. Samerecipe_nameon every row, layer name inpart. If the recipe has a single layer, leavepartempty. filling_typemust be the exact identifier, lowercase with underscores. Plainganacheis not valid; the classic bonbon ganache isganache_bombon. The full list lives in the Quick guide block on the screen itself.
The wizard, step by step
The wizard is titled "Import recipes from CSV" and has five screens.
Upload. Drag the file onto the "Drag your file here" zone or click to browse. It accepts .csv and .xlsx, and one file per import (the picker does not allow multiple selection).
Map. A table with three columns — File column, Example and AreaCacao field — where you pick a destination for each header. It arrives pre-filled by the wizard's own detection, which recognises Spanish and English synonyms regardless of case or accents (Nombre de la receta, recipe name, receta… all resolve to recipe_name).
Columns you don't need stay on Skip. The same AreaCacao field cannot be assigned to two columns: picking it on one clears it from the other.
If you haven't mapped the recipe name, the wizard won't let you continue and shows: "Tell us at least which column holds the recipe name to continue."
Options. You choose what happens to ingredients we can't find. See the next section.
Preview. The server works out what would happen without writing anything: "Here's what we'll do. Nothing has been saved yet." You get counts for Recipes total, Recipes to create, Recipes to update, Ingredients linked, Ingredients to create, Ingredients pending and Supplies not found, plus an Issues found list keyed by row number.
Import. You press Import and the job moves to the background. The screen polls its status every 2.5 seconds until it finishes and shows "Import complete" with the summary "N created · N updated · N with errors."
Ingredients that don't match the catalog
The importer resolves each row like this: if there's an ingredient_code, it looks that exact record up; otherwise it searches your catalog by name. When nothing matches, it applies the choice you made in the Options step:
- Create missing ingredients as pending (no cost) — "Ingredients we can't find are added marked as pending, with no nutrition or cost data. You can complete them later. Uses no credits." This is the default.
- Auto-complete missing ingredients with AI — 5 credits per ingredient — "For each ingredient we can't find, AI estimates macros, allergens and cost data. Charged 5 credits per new ingredient."
The AI mode is the only way this route can consume credits, and the charge is per new ingredient — not per recipe and not per file. The pending mode never touches your credits.
Supplies
Rows flagged with is_supply or carrying a supply_code are treated as supplies. They are linked by code only against your supplies catalog. If the code doesn't exist, the line is still imported but flagged for review, and the Supplies not found count in the preview warns you beforehand. The importer never creates new supplies — not even in AI mode, which only applies to ingredients.
Create versus update
- No
recipe_id→ a new recipe is always created. - With
recipe_id→ if that id exists and is yours, the recipe is updated. If it doesn't exist or isn't yours, a new recipe is created instead. - When a recipe is created and its name already exists in your catalog, AreaCacao differentiates the name automatically rather than blindly duplicating it. This applies on create only, never on update.
- One failing recipe does not abort the batch: it is flagged with its error and the importer moves on to the next one.
Limits
| Limit | Value |
|---|---|
| Formats | .csv and .xlsx |
| Files per import | 1 |
| Maximum file size | 20 MB |
| Maximum data rows | 20,000 (header excluded) |
Sheets read from an .xlsx | The first one only |
| Concurrent imports | 1 per user |
| Rate limit | 20 upload/parse operations per 10 minutes, per user |
If you try to start an import while another one is queued or processing, the server rejects it: you have to wait for the previous one to finish.
What it does NOT do
- It does not read your file with AI. The column mapping is yours and the parsing is deterministic.
- It does not appear in the History tab. That tab lists photo and PDF imports. Spreadsheet imports are not listed on any screen: their status is only visible in the wizard window while you keep it open. If you close it, the import carries on, but you'll have to check My recipes to see the result.
- It cannot be cancelled. Once you press Import there is no cancel button; the wizard only lets you close the window.
- It does not create new supplies.
- It does not read more than one sheet from an Excel workbook.
- It does not import from a Google Sheets link or any URL: the file has to be uploaded. Importing from a web page is a separate route — see Import a recipe from a URL.
- It does not validate
filling_typefor you. If you write an identifier that doesn't exist, the recipe is imported without filling-specific technical validation.