--- name: linkedin:import description: | Import a LinkedIn analytics CSV export into the structured analytics system. Parses CSV, converts to JSON, detects anomalies, and prepares data for trend analysis. Now with auto-detect from ~/Downloads, quick-import browser helper, and analytics-to-strategy feedback loop. Use when the user wants to import analytics data from LinkedIn. Triggers on: "import analytics", "import CSV", "upload analytics", "parse LinkedIn data", "add analytics export", "import my LinkedIn data". allowed-tools: - Bash - Read - Glob - Write - AskUserQuestion --- # LinkedIn Analytics Import Workflow You are a LinkedIn analytics data import assistant. Guide the user through importing their LinkedIn analytics CSV export with minimal friction. ## Reference For data format details and directory structure, see `assets/analytics/README.md`. > **Why CSV (as of 2026-05).** Post-level analytics via LinkedIn's API is > partner-gated (vetted Community Management app + verified org + Page) and **not > self-serve** for a personal profile, so the CSV export is the practical floor. > Saves are visible in native post analytics (count-only) but have no self-serve > API pull; dwell is internal-only for organic posts. See the README boundaries. ## Step 1: Check for CSV Files in Exports Directory First, check if any CSV files exist in the exports directory: ```bash ls -lh ${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/exports/*.csv 2>/dev/null || echo "No CSV files found" ``` **If files found:** Skip to Step 3. ## Step 1b: Auto-Detect from ~/Downloads If no files in exports directory, scan `~/Downloads/` for recent LinkedIn CSV files: ```bash find ~/Downloads -maxdepth 1 -name "*.csv" -mtime -14 -type f 2>/dev/null | sort -t/ -k$(echo ~/Downloads/x | tr '/' '\n' | wc -l) | head -10 ``` Filter results for LinkedIn-looking files (filenames containing 'linkedin', 'analytics', 'content', 'export', or any CSV modified in the last 24 hours). **If matching files found**, present them using AskUserQuestion: Options: - **Import specific file** — Select one of the detected files - **Import all** — Import all matching CSV files - **Quick-import** — Open LinkedIn Analytics in browser and auto-detect download - **Skip** — Show manual instructions instead On file selection, copy the file to the exports directory: ```bash cp "" ${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/exports/ ``` Then continue to Step 4. ## Step 2: If No Files Found Anywhere If no CSV files exist in exports or ~/Downloads, offer two options: **Option A: Quick-import (recommended)** Run the quick-import helper that opens LinkedIn Analytics in the browser and watches for the download: ```bash node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/quick-import.mjs ``` This will: 1. Open `linkedin.com/analytics/creator/content/` in your browser 2. Watch ~/Downloads for new CSV files 3. Auto-copy detected files to the exports directory After the script completes, continue to Step 4. **Option B: Manual export** 1. Go to [linkedin.com/analytics/creator/content/](https://linkedin.com/analytics/creator/content/) 2. Click the **"Export"** button (top right) 3. LinkedIn will download a CSV file 4. Move it to: `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/exports/` ```bash mv ~/Downloads/linkedin_analytics_export*.csv ${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/exports/ ``` Once done, run `/linkedin:import` again. ## Step 3: Select Files to Import If CSV files exist in the exports directory: 1. **List the files** with details (name, size, date) 2. **Ask the user** which file to import using AskUserQuestion: Options: - **Latest** — Import the most recent file only - **All** — Import all CSV files - **Select** — Choose a specific file - **Cancel** — Exit import ## Step 4: Run Import The import CLI runs under `tsx` and depends on `csv-parse`. Both live in the **gitignored** `scripts/analytics/node_modules/`, so on a fresh clone they are absent and the CLI would crash with `ERR_MODULE_NOT_FOUND`. Install them once first (idempotent — a fast no-op when already present): ```bash cd "${CLAUDE_PLUGIN_ROOT}/scripts/analytics" && npm install --silent ``` Once the user selects, run the import CLI: ```bash "${CLAUDE_PLUGIN_ROOT}/scripts/analytics/node_modules/.bin/tsx" "${CLAUDE_PLUGIN_ROOT}/scripts/analytics/src/cli.ts" import ``` If importing multiple files, run the command for each file sequentially. ## Step 5: Capture and Present Results The CLI prints (see `cli.ts` `handleImport`): - `Posts imported:` — count of valid rows (rows with an empty title or an unparseable date are skipped, each with a `Warning:` line) - `Date range:` — earliest to latest post in the batch - `Batch ID:` and `Saved to: posts/` — the batch file written - `Saves entered:` — only when the CSV carried a `Saves` column (manual entry) - An anomaly block — either `Immediate alerts detected:` with 🔴/⚠️/ℹ️ spike/drop lines, or `No anomalies detected in imported data.` **Surface the CLI's output to the user** — for example: ``` Import successful! ───────────────────────────────────── Posts imported: 42 Date range: 2025-12-01 to 2026-01-29 Saved to: posts/2025-12-01-batch-a1b2c3d4.json Saves entered: 1,204 across 18 post(s) (manual) Immediate alerts detected: ───────────────────────────────────── ℹ️ [INFO] Post "AI agents are eating..." has unusually high impressions: 21,400 (2.4 std deviations above mean) ``` The saved file is named `posts/YYYY-MM-DD-.json` (the batch's earliest post date + a short batch id), not by ISO week. ### Step 5b: Surface the Anomalies the Importer Detected The import CLI runs **intra-batch** anomaly detection during Step 4 (`detectAlerts` in `cli.ts`): for the just-imported batch it flags any post whose impressions deviate sharply — by standard deviation — from *that batch's own mean*, printing either `Immediate alerts detected:` (🔴/⚠️/ℹ️ spike/drop lines) or `No anomalies detected in imported data.` Surface those lines as-is, and state the scope honestly: a flagged post stands out **among the posts in this export**, not against a stored historical baseline — the importer keeps no baseline file. Cross-week comparison is Step 6's job. **Present as:** ``` ### Import Summary — X posts imported (Y skipped: empty title or unparseable date) #### Standout in this batch ℹ️ "[hook text...]" — 21,400 impressions (2.4 std dev above this batch's mean) ⚠️ "[hook text...]" — 180 impressions (2.1 std dev below this batch's mean) (or: "No standout deviations within this batch.") ``` Cross-week analysis — best day of week, format performance, week-over-week trend, rolling averages — is **not** computed here; it is produced by `/linkedin:report` (Step 6), which reads the full post history via the `trends`/`heatmap` CLI. Defer that analysis to Step 6 rather than restating it. ## Step 6: Analytics-to-Strategy Feedback Loop After successful import, the analysis fan-out (pillar performance, format performance, day-of-week heatmap, actionable recommendations) is **delegated to `/linkedin:report`** — both commands consume the same `trends` CLI from `scripts/analytics/`, and keeping a second analysis pipeline here drifted out of sync with `report.md`. ### Step 6a: Run the report Invoke the report generator and surface its output inline: ``` Run /linkedin:report (period: 4w) ``` `/linkedin:report` will: 1. Read `expertise_areas` from `~/.claude/linkedin-studio.local.md` 2. Call `trends` for impressions and engagement_rate over the last 4 weeks: ```bash "${CLAUDE_PLUGIN_ROOT}/scripts/analytics/node_modules/.bin/tsx" "${CLAUDE_PLUGIN_ROOT}/scripts/analytics/src/cli.ts" trends --period 4w --metric impressions "${CLAUDE_PLUGIN_ROOT}/scripts/analytics/node_modules/.bin/tsx" "${CLAUDE_PLUGIN_ROOT}/scripts/analytics/src/cli.ts" trends --period 4w --metric engagement_rate ``` 3. Produce the Content Pillar Performance, Format Performance, and Day-of-Week Performance tables, plus exactly 3 actionable recommendations 4. Return its summary back to this import flow If `/linkedin:report` is unavailable (analytics dir empty, tsx missing), fall back to a one-line status: "Import complete — run `/linkedin:report` manually when analytics are ready." ### Step 6b: Update State with Import Date After successful import and analysis, update the state file: ``` Read ~/.claude/linkedin-studio.local.md Set last_import_date to today (YYYY-MM-DD) Set last_import_week to current ISO week (YYYY-WXX) Write the updated state file ``` ## Step 7: Next Steps Present next steps using AskUserQuestion based on the analysis results: **If the report's trend is down** (impressions or engagement trending DOWN): - "Run /linkedin:report for full weekly breakdown" - "Run content audit to review strategy" - "Analyze your top post to understand what worked" **If the report's trend is up** (impressions or engagement trending UP): - "Run /linkedin:report for the full numbers" - "Create more content in your top format" - "Draft your next post while insights are fresh" **If first import:** - "Run /linkedin:report for your first performance report" - "Import 2-3 more weeks for trend analysis" - "Tip: Export weekly every Monday for best tracking" **If mixed results:** - "Run /linkedin:report for complete breakdown" - "Review trend analysis for diverging metrics" - "Check which formats and topics drove results" Present using AskUserQuestion with the top 3 most relevant suggestions. ## Step 8: Demographics Sync Suggestion After completing the import workflow, check if `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/audience-insights/demographics.md` still has placeholder data: ```bash grep -c '\[Industry name\]\|\[Function\]\|\[Country\]\|\[X\]%' ${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/audience-insights/demographics.md 2>/dev/null ``` If placeholder count is > 10 (still mostly unfilled), suggest: "While you're in LinkedIn Analytics exporting CSV data, you can also capture your audience demographics. Run `/linkedin:setup` and choose option 5 (Demographics) to fill in your audience insights with real data." ## Error Handling If the import fails: 1. **Check the CSV format** - LinkedIn sometimes changes export format 2. **Verify the file path** - Ensure the file is in `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/exports/` 3. **Check file permissions** - The CLI needs read access 4. **Show the error message** and suggest solutions **Common errors:** - `File not found`: Check the filename (case-sensitive) - `Invalid CSV format`: Verify this is a LinkedIn analytics export - `Permission denied`: Check file permissions with `ls -l` ## Reference Files The import system creates: - `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/analytics/posts/YYYY-MM-DD-.json` - one JSON batch per import (earliest post date + short batch id) Weekly and monthly report files (under `weekly-reports/` and `monthly-reports/`) are created separately by `/linkedin:report`, not by import. ## State Tracking After import: - A new batch file `posts/YYYY-MM-DD-.json` is written, one per import — existing batch files are never overwritten; `loadAllPosts` deduplicates by post id at read time (latest import wins) - Intra-batch spike/drop alerts are computed and surfaced (std deviation from the batch's own mean — no persisted baseline) - `last_import_date` and `last_import_week` are updated in the state file (`~/.claude/linkedin-studio.local.md`, see Step 6b)