GuidesBulk scheduling with CSV: validate every row before any import
A portable CSV staging contract for Arabic text, UTF-8, media URLs, time zones, row validation, dry runs, and rollback—without promising an unsupported importer.
Last updated September 3, 2026 · 9 min read · The Naasher team · Editorial and corrections policy (Arabic) · اقرأ بالعربية
Answer first: Naasher does not currently promise a general CSV import path. Use CSV as a portable, validated staging file for migration or controlled tooling only. Preserve UTF-8, quote multiline Arabic correctly, normalize time into UTC with its source zone, verify provider-reachable media, dry-run every row, and keep a rollback map before any scheduler accepts the batch.
Separate portable columns from provider-specific behavior
A durable CSV describes intent without pretending every network shares one publishing model.
| Class | Examples | Rule |
|---|---|---|
| Portable identity | client_row_id, workspace_ref, account_ref, provider | Use stable references; resolve and display the exact destination in dry run |
| Portable content | body, alt_text, media_url, scheduled_at_utc, source_timezone | UTF-8 text with explicit quoting and time semantics |
| Campaign context | campaign_ref, language, approved_version, utm_source, utm_campaign | Retain for review; never silently rewrite approved links |
| Provider-specific | privacy, first comment, poll choices, location, thread position | Validate through an explicit adapter; blank does not mean supported default |
| Nonportable evidence | approval history, provider IDs, media binaries, comments, analytics snapshots | Move separately with provenance; do not flatten into one cell |
Use a unique client_row_id so dry-run errors, approval, scheduling results, and rollback decisions refer to the same source row. Do not use row number as identity; sorting changes it.
Preserve Arabic, emoji, and line breaks
Save UTF-8. A UTF-8 BOM can help spreadsheet software recognize Arabic, but the receiving parser must tolerate and strip it from the first header. Record the delimiter. The Arabic comma ، belongs to content and is not the same as the ASCII CSV delimiter ,.
Quote any field that contains a comma, Arabic comma plus surrounding CSV punctuation, double quote, or line break. Escape a literal double quote by doubling it. Keep hashtags and emoji as Unicode; do not replace them with lossy legacy encodings. Normalize line endings at ingestion while preserving intentional line breaks inside the quoted body.
client_row_id,account_ref,body,scheduled_at_utc,source_timezone,media_url
launch-017,riyadh-linkedin,"أطلقنا النسخة الجديدة، اليوم 🚀
التفاصيل: https://example.com/release",2026-09-03T06:00:00Z,Asia/Riyadh,https://media.example.com/launch-017.jpg
Check Unicode normalization for visually similar Arabic sequences and keep a test fixture containing Arabic-Indic and Western digits, hashtags, emoji, a quoted phrase, a URL with UTM parameters, and a multiline caption. Review the rendered preview; byte-valid text can still be directionally confusing.
Convert time with a named zone
For the worked fixture above, 2026-09-03 09:00 in Asia/Riyadh maps to 2026-09-03T06:00:00Z. Calculate this with a current time-zone library; do not hard-code a permanent offset rule. Store both the canonical UTC instant and the source IANA zone, and show the approver the local date and time again.
Reject ambiguous local input such as 09/03/26 9:00, a missing zone, or a locale-dependent spreadsheet date serial. Define the accepted ISO format, then parse strictly.
Make media reachable and auditable
A media URL must use HTTPS, return the intended file rather than an HTML login page, expose the right content type, and remain reachable through the provider's upload and processing window. A URL that works in the operator's signed-in browser may fail from a provider worker.
Prefer the product's supported upload flow when available. Otherwise use a controlled, time-bounded URL with enough lifetime, no personal query token in logs, and a retained asset digest. Validate dimensions, size, codec, alt text, and rights per target before scheduling.
Run a deterministic dry run
The dry run must make no external publishing mutation. For every row it should:
- Parse encoding, header, delimiter, quotes, and required fields.
- Resolve workspace and account allowlists without printing credentials.
- Validate UTC and display the source-zone interpretation.
- Validate text, link domains, media reachability, and target capabilities.
- Match the exact approved version and flag edits.
- Produce
ready,blocked, orneeds reviewwith reason codes.
Do not schedule the valid subset silently when blocked rows share one approval decision. The operator must choose whether partial acceptance is allowed and record that choice.
Use validation fixtures before customer data
Maintain fixtures for a valid Arabic multiline row, UTF-8 BOM, missing account, duplicate client_row_id, bad quote, expired media URL, unsupported provider column, invalid UTC, repeated source row, and edited approved link. The expected result should include a stable error code and no write.
Then test one low-risk row end to end. Require a local schedule identifier, per-target provider outcome, and remote visible result. A created local row is not proof of publication.
Plan rollback before importing
Keep an immutable source file digest, import/batch ID, row-to-local-ID map, authorizer, and timestamp. Rollback must distinguish unscheduled records, queued jobs, provider-accepted requests, and live posts. Cancel locally only when still safe; do not assume deleting a scheduler record removes a provider post.
If a batch is partially successful, stop the importer, reconcile every target, and retry only the confirmed failed subset. Follow the publishing incident runbook for late success and uncertain outcomes, and the migration runbook before disabling the old scheduler.
Naasher product limit and safe next step
Naasher supports composing and scheduling through its current UI and scoped API/MCP surfaces on eligible plans, but it does not currently advertise a general customer CSV importer. Do not build a customer migration promise around an internal script, a file shape from another product, or this guide.
Use this contract to clean and review data, then recreate approved items through documented product paths unless the live workspace exposes a supported importer with its own schema, validation, and rollback contract. For Arabic preview details, use the mixed-direction guide; for agent-generated batches, require the controls in AI agent publishing safety.
Release checklist
- Encoding and delimiter are explicit; BOM behavior is tested.
- Multiline Arabic, commas, hashtags, emoji, quotes, digits, and URLs round-trip.
- Every account resolves to an allowed destination.
- UTC and the named source zone agree in the preview.
- Media remains provider-reachable and matches target constraints.
- Dry run produces stable row decisions without writes.
- Approval binds the exact file digest and accepted rows.
- Rollback maps every row to local and remote state.
- Unsupported columns and missing evidence stay blocked, not guessed.
A bulk workflow is ready when one rejected row can be explained and one accepted row can be reversed safely—not when a spreadsheet merely opens without mojibake.
Frequently asked questions
- Does Naasher currently support general CSV import for bulk scheduling?
- Naasher does not currently promise a general CSV import contract. Treat CSV as a validated staging and migration artifact unless the current product UI and documentation explicitly expose an importer for your workspace.
- Should a CSV store Riyadh local time or UTC?
- Store a canonical UTC instant and retain the named source zone such as Asia/Riyadh. Generate both with a time-zone-aware library and show the local interpretation in the dry run.
- Can media use a private dashboard URL?
- Not if the provider must fetch it directly. Use a time-bounded HTTPS URL that remains reachable for the full processing window, or upload through the product's supported media flow.