SkillMachine
All skills

Etsy Keyword Researcher

Data & Research apify

Extracts a keyword universe + demand proxy + clusters from Etsy autocomplete.

Live output preview

A plan is required to view this content

Choose a plan to access input format, sample outputs, and live previews.

View Plans →

About the skill

/etsy-keywords-apify-fetcher — Library Skill: Etsy Autocomplete Keyword Universe

A standard, agent-facing interface to the Apify maximedupre/etsy-keywords-research-tool actor (APIFY_ETSY_KEYWORDS_ACTOR env override). In a single call (the actor accepts a keywords[] array), it expands a seed list into the Etsy search bar's autocomplete suggestions, dedupes them, and produces a relative demand proxy.

v2.0.0 — actor changed. The previous easyapi/etsy-keywords-research-tool actor was running but returning 0 results (backend down, confirmed 2026-06-14). It was replaced with the working + cheaper + better-schema'd maximedupre/etsy-keywords-research-tool (array input, rank, normalizedSuggestion, alphabet expansion).

⚠️ Data Reality — Read First

  • This actor does NOT give ABSOLUTE search volume. Etsy's official API does not expose search volume; no free source gives the true in-Etsy monthly search count.
  • The signal it returns: the terms real buyers type, from Etsy autocomplete, ordered by autocomplete position (rank). best_rank=1 = what Etsy suggests at the very top for that seed = the strongest demand signal.
  • The caller must NOT present it as "X searches per month." The correct framing is: "relative demand ranking / autocomplete position."
  • Competitor supply / sales counts are NOT in this actor → for that, automation-lab/etsy-scraper (listing + price + rating) is used separately.

How It's Called

Skill tool: etsy-keywords-apify-fetcher
Input: {
  seeds: <string[]>,               // ["gothic shirt","witchy tee",...] — all in a SINGLE call
  country?: <ISO-3166-1>,          // default "US" (Etsy is US-heavy)
  language?: <ISO-639-1>,          // default "en"
  max_results_per_seed?: <int>,    // default 30, clamp [10,80]
  expand_prefixes?: <bool>,        // default false; true = seed + a-z (MORE results + MORE cost)
  prefix_characters?: <string>,    // default "abcdefghijklmnopqrstuvwxyz"
  max_retries?: <int>,             // retry if empty, default 2
  min_breadth?: <int>,             // lower bound for seed_breadth in results, default 1
  output_path?: <abs path>         // stdout JSON if absent
}

Credentials & Prerequisites

set -e
ENV_FILE="$HOME/.claude/.env"
[ -f "$ENV_FILE" ] || { echo "FAIL: $ENV_FILE yok" >&2; exit 1; }
APIFY_API_TOKEN=$(grep -E '^APIFY_API_TOKEN=' "$ENV_FILE" | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'")
APIFY_ETSY_KEYWORDS_ACTOR=$(grep -E '^APIFY_ETSY_KEYWORDS_ACTOR=' "$ENV_FILE" | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'")
[ -n "$APIFY_ETSY_KEYWORDS_ACTOR" ] || APIFY_ETSY_KEYWORDS_ACTOR="maximedupre/etsy-keywords-research-tool"
[ -n "$APIFY_API_TOKEN" ] || { echo "FAIL: APIFY_API_TOKEN boş" >&2; exit 1; }
command -v jq >/dev/null || { echo "FAIL: jq yok" >&2; exit 1; }

Flow

1. Input Validation

  • seeds is required, 1-40 range. Duplicate seed → dedupe, trim.
  • country/language default "US"/"en". max_results_per_seed clamp [10,80]. expand_prefixes default false (if true, results and cost increase ~5-10x). min_breadth default 1.

2. Cost / Quota Note

Pay-per-result: ~$0.00265 / keyword result (≈ $2.65/1000) + a small actor-start. Rough estimate: 15 seeds × 30 results ≈ 450 results ≈ ~$1.2. expand_prefixes:true multiplies this many times over — turn it on only when deep coverage is needed.

3. Apify run-sync — SINGLE CALL (array input)

ACTOR_SLUG=$(echo "$APIFY_ETSY_KEYWORDS_ACTOR" | tr '/' '~')   # maximedupre~etsy-keywords-research-tool
PER="${max_results_per_seed:-30}"
COUNTRY="${country:-US}"; LANG="${language:-en}"
EXP="${expand_prefixes:-false}"; PREFIX="${prefix_characters:-abcdefghijklmnopqrstuvwxyz}"
MAX_RETRIES="${max_retries:-2}"
SEED_COUNT=${#seeds[@]}
TOT=$(( PER * SEED_COUNT )); [ "$TOT" -lt 30 ] && TOT=30

SEEDS_JSON=$(printf '%s\n' "${seeds[@]}" | jq -R . | jq -s 'map(select(length>0)) | unique')
PAYLOAD=$(jq -n --argjson kw "$SEEDS_JSON" --argjson n "$PER" --argjson tot "$TOT" \
  --argjson exp "$EXP" --arg pc "$PREFIX" --arg c "$COUNTRY" --arg l "$LANG" '{
    keywords: $kw,
    maxResultsPerKeyword: $n,
    maxTotalResults: $tot,
    expandPrefixes: $exp,
    prefixCharacters: $pc,
    sortOutputBy: "sourceOrder",
    country: $c,
    language: $l,
    includeNormalizedKeyword: true,
    includeSearchUrls: true
  }')

RAW=$(mktemp -t etsy-kw-raw.XXXXXX.json); attempt=0; count=0
while [ "$attempt" -le "$MAX_RETRIES" ]; do
  attempt=$((attempt+1))
  if curl -fsS -X POST \
      "https://api.apify.com/v2/acts/${ACTOR_SLUG}/run-sync-get-dataset-items?token=${APIFY_API_TOKEN}&timeout=240&format=json&clean=true" \
      -H "Content-Type: application/json" --data "$PAYLOAD" --max-time 300 > "$RAW" 2>/dev/null; then
    if jq -e 'type=="array"' "$RAW" >/dev/null 2>&1; then count=$(jq 'length' "$RAW"); [ "$count" -gt 0 ] && break; fi
  fi
  echo "[warn] attempt $attempt → 0/err" >&2
done

⚠️ Because this actor takes a keywords[] array, multiple seeds = a single run (in the old actor each seed was a separate run). If it returns empty, retry up to max_retries.

4. Dedupe + Demand Proxy + Sort

MIN_BREADTH="${min_breadth:-1}"
FINAL_KW=$(jq --argjson minb "$MIN_BREADTH" '
  group_by(.normalizedSuggestion // (.suggestion | ascii_downcase))
  | map({
      suggestion: .[0].suggestion,
      normalized: (.[0].normalizedSuggestion // (.[0].suggestion | ascii_downcase)),
      type: (.[0].suggestionType // "autocomplete"),
      best_rank: (map(.rank // .sourceRank // 999) | min),
      seed_breadth: (map(.seedKeyword) | unique | length),
      seeds: (map(.seedKeyword) | unique),
      search_url: (.[0].searchUrl // null),
      demand_proxy_score: ((100.0 / (map(.rank // .sourceRank // 999) | min)) | floor)
    })
  | map(select(.seed_breadth >= $minb))
  | sort_by(-(.seed_breadth), .best_rank)
' "$RAW")

# seed_diagnostics: which seed returned results / empty
DIAG=$(jq -n --argjson raw "$(cat "$RAW")" --argjson req "$SEEDS_JSON" '
  ($raw | group_by(.seedKeyword) | map({key:.[0].seedKeyword, value:length}) | from_entries) as $hit
  | $req | map({seed:., status:(if ($hit[.] // 0) > 0 then "ok" else "no_data" end), count:($hit[.

How do I use this skill?

You don't "run" a skill — after installing it you just tell the agent your task (e.g. ask for the relevant job), and the skill kicks in by itself when its description matches.

Upload the etsy-keywords-apify-fetcher.zip you downloaded as-is — no packaging needed, the format is already correct (folder at root).

  1. Open Settings → Customize → Skills
  2. Upload → select the etsy-keywords-apify-fetcher.zip you downloaded
  3. Claude reads SKILL.md; the name + description appear. Ready ✅

Scripts run in Anthropic's code-execution environment (sandbox) — not on your machine.