Quora Scraper — Webhook Delivery & Demo Mode avatar

Quora Scraper — Webhook Delivery & Demo Mode

Pricing

from $4.99 / 1,000 results

Go to Apify Store
Quora Scraper — Webhook Delivery & Demo Mode

Quora Scraper — Webhook Delivery & Demo Mode

🚀 Quora Scraper extracts Questions, Answers, Profiles, Topics & Spaces from Quora—organized, searchable, and ready for research, lead gen & content insights. 📈 Fast, reliable, and scalable for data-driven teams.

Pricing

from $4.99 / 1,000 results

Rating

0.0

(0)

Developer

Scraper Engine

Scraper Engine

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

9 days ago

Last modified

Share

Quora Scraper — Answers, Upvotes and Authors with Webhook Delivery

Quora Scraper turns a keyword or a Quora URL into structured JSON rows: question title, full answer text, author name and credentials, upvotes, comment and share counts, follower counts and topic tags. It covers five content types — questions, answers, profiles, topics and spaces — needs no Quora account, login or cookie, and can POST every row to your own endpoint as it is produced. Paste a keyword, set a row limit, press Start.

⚠️ Demo Mode does not scrape Quora. It emits six hard-coded sample rows made of invented values. With demoMode set to true the Actor never opens a single Quora page: it pushes one question row, two answer rows, one profile, one topic and one space row built from literals in the source — an author called Sample Human Author, upvotes of 2400, follower_count of 15230, and text fields that say SAMPLE demo data in them. Those rows use exactly the same keys as real rows and carry no flag marking them synthetic, so if you also set webhookUrl your downstream system receives fabricated Quora data through the same channel as real data. Demo rows are pushed without a charge event attached, which is the point of the feature — it is a free format preview, not a free sample of Quora. Never treat a demo dataset as Quora content.

What is Quora Scraper — Webhook Delivery & Demo Mode?

Quora Scraper — Webhook Delivery & Demo Mode is an Apify Actor that reads public Quora pages with a browser-impersonating HTTP client, pulls the GraphQL payloads Quora embeds in them, and flattens each result into a typed dataset row tagged with a content_type of question, answer, profile, topic or space. On top of that it adds two pipeline features named in its title: webhookUrl, which POSTs each row to an endpoint you supply the moment it is written, and demoMode, which emits sample rows for free instead of scraping.

No Quora account, login or cookie is required. The Actor never authenticates — it reads exactly what a logged-out visitor's page contains.

It is built for developers wiring Quora into an existing pipeline, content and SEO researchers mining question intent, and AI engineers feeding Q&A text into retrieval or evaluation sets.

What Quora question and answer data is publicly available to scrape?

A logged-out Quora question page carries the question title, its topic tags, its answer and follower counts, and the full text of its answers along with each author's display name, profile link, credential line and engagement metrics. Profile, topic and space pages expose their own counters to anonymous visitors, and this Actor reads all of them.

Data CategoryPublicly AvailableBehind a Quora login or paid Quora account
Question title, URL, topic tags, answer count, follower count✅ Public
Full answer text, author name, profile link, credential line✅ Public
Answer upvotes, displayed comment count, share count, relative post age✅ Public
Profile name, bio, credentials, followers, following, answers asked and written, all-time views✅ Public
Topic and Space name, description, follower / question / post / contributor counts✅ Public
Comment bodies under an answerNot returned — only the count, in comments_count
Upvoter identities and per-answer view countsNot in the logged-out payload — never returned
Quora's own on-site search results pageNot used — URLs are discovered through DuckDuckGo instead

Quora Scraper — Webhook Delivery & Demo Mode only returns publicly visible data — what any visitor sees. Nothing behind a login wall.

What data can I extract with Quora Scraper — Webhook Delivery & Demo Mode?

Every row carries content_type, title, url, source_url and scrape_timestamp. Everything else depends on which of the five content types the row is, so the dataset is intentionally sparse — branch on content_type before you read anything else. Across all five row builders the Actor writes 32 distinct keys.

Field NameDescription
content_typeRow type: question, answer, profile, topic or space. On every row
titleQuestion title on question and answer rows; person, topic or space name on the other three. On every row
urlCanonical Quora link for the row — answer permalink, question, profile, topic or space page. On every row
source_urlThe URL the Actor opened to produce this row — the discovered or pasted URL, not the canonical one
scrape_timestampUTC ISO-8601 stamp of when the Actor wrote the row — the Actor's clock, not Quora's
source_queryThe keyword that discovered this row, "" for direct URLs. On question and answer rows only
answer_countAnswers on the question (question rows) or public answers written by the person (profile rows)
follow_countFollowers of the question. On question rows only — note the name differs from follower_count
topicsArray of Quora topic names attached to the question, [] when none are exposed
answer_textFull answer body flattened from Quora's rich-text document to plain text, not truncated
answer_urlDirect permalink to the answer itself
author_nameAnswer author's display name, assembled from Quora's givenName + familyName
author_urlAnswer author's Quora profile URL, "" when Quora's node carries none
author_credentialsThe author's credential line as Quora displays it, "" when absent
upvotesUpvote count on the answer, null when Quora omits the counter
comments_countDisplayed comment count on the answer, null when Quora omits the counter
shares_countShare count on the answer, null when Quora omits the counter
answer_timestampRelative age string derived from Quora's creationTime3y, 5mo, 2w, 4d, 7h, 12m
is_ai_answertrue when Quora flags the answer as machine-generated
question_titleTitle of the question the answer sits under — identical to title on answer rows
question_urlURL of the question the answer sits under
namePerson, topic or space name. On profile, topic and space rows — duplicates title
bioProfile biography, flattened from Quora's rich-text document to plain text
credentialsProfile credential line, flattened to plain text
profile_image_urlAvatar image URL
follower_countFollowers of the profile, topic or space
following_countAccounts the profile follows
question_countQuestions asked by the profile, or questions filed under the topic
total_viewsAll-time public content views for the profile
descriptionTopic or space description, flattened to plain text
post_countPosts in the space. On space rows only
contributor_countContributors to the space. On space rows only

follow_count on question rows and follower_count on profile, topic and space rows are two different keys for the same idea. The default Overview (All) view shows neither — it maps its columns to author_name, upvotes and comments_count, which only answer rows carry, so question, profile, topic and space rows look half-empty there. Switch to the per-type views for the full picture.

Question and answer text fields

question rows are the header for a page: title, url, answer_count, follow_count and topics. answer rows carry the substance — answer_text is the complete flattened answer body, never a snippet, and question_title / question_url repeat the parent question so an answer row stands on its own with no join.

title and question_title are set from the same value on answer rows, so they are always equal, and url and answer_url are set from the same resolved permalink, so those are always equal too. When Quora's node carries neither url nor permaUrl, both come back as "" rather than falling back to the question link.

Engagement, timestamp and flag fields

upvotes, comments_count and shares_count come straight from Quora's own counters (numUpvotes, numDisplayComments, numShares) and are passed through unchanged — if the counter is missing from the payload the key is null, not 0, so an empty value means "not published" rather than "no engagement". Answer view counts are not part of the logged-out payload and are not returned.

answer_timestamp is the only date field. It is derived from Quora's microsecond creationTime into the same relative string Quora itself shows — 3y, 5mo, 2w, 4d, 7h, 12m — and is "" when creationTime is absent. There is no absolute date field on this Actor; if you need an ISO-8601 answer date and an age in days, the sibling Quora Search Scraper returns created_at and age_days. is_ai_answer reflects Quora's own machine-answer flag and is always a real boolean.

Profile, topic and space fields

profile rows carry name, bio, credentials, profile_image_url, follower_count, following_count, answer_count, question_count and total_views. topic rows carry name, description, follower_count and question_count. space rows swap in post_count and contributor_count. Bios, credentials and descriptions all arrive as Quora rich-text documents and are flattened to plain text before they reach you; an embedded image inside a bio becomes an [image: <url>] marker on its own line.

Unlike keyword discovery in some Quora Actors, this one does not filter its search results down to question pages — any quora.com URL the search engine returns is classified by its path and scraped, so a keyword run can produce profile, topic and space rows as well as questions and answers.

🤖 Add-on: Need additional Quora data?

Quora Search Scraper covers the same five content types with a global result budget and absolute answer dates, which is the better fit when you want one predictable row count per run rather than a per-target one. For the same question-intent research on other platforms, Reddit Posts Scraper By Keyword & Score Filter and YouTube Search Scraper surface what an audience is asking elsewhere.

Why not build this yourself?

Quora publishes no public content API, so there is no supported endpoint to point at — which means a DIY build inherits every one of the problems this Actor already solves.

The page is not the data. Quora ships its content as GraphQL payloads embedded in .push("…") calls inside the HTML, double-escaped, alongside a near-empty stub of the same shape that a throttle or challenge response also carries. The Actor extracts and parses every blob, then checks that the object actually has real fields in it — a page that returns HTTP 200 and looks fine is rejected unless the question, user, topic or tribe node carries genuine values.

Requests have to look like Chrome. Plain HTTP clients get challenged. Egress runs through curl_cffi with a chrome131 TLS and header fingerprint, a 40-second request timeout, and a warm-up pattern — Quora frequently serves real data only on the second request to a session, so each exit IP gets up to three tries with a short pause between them.

Deep answer pulls need tokens you have to go and find. To page through answers the Actor scrapes the formkey and the question's GraphQL node id out of the rendered page, then fetches the referenced JS bundle to recover the 64-character persisted-query hash, then drives QuestionPagedListPaginationQuery in batches of up to 20 over the same sticky exit IP, parsing Quora's multipart/mixed response boundary by hand.

Discovery is a separate problem from extraction. Quora's own search box is not used at all. For each keyword the Actor negotiates a DuckDuckGo vqd token, then paginates the links.duckduckgo.com/d.js endpoint with site:quora.com <your keyword>, stopping when DuckDuckGo returns its anomalyDetectionBlock marker.

Proxies, retries and a browser you did not want to run. Every run climbs an automatic ladder — direct, then Apify datacenter, then Apify residential, sticky once escalated — with six further fresh residential exit IPs before it gives up, and an optional headless Chromium last resort for pages that are hard-blocked even then. You never create a proxy account, rotate an IP or maintain a browser image.

How to use Quora Scraper — Webhook Delivery & Demo Mode

The Actor runs on Apify. Start it from the Apify Console or call it through the Apify API. No Quora credentials are involved at any point.

  1. Open Quora Scraper — Webhook Delivery & Demo Mode on Apify and click Try for free
  2. Optionally switch Demo Mode (demoMode) on for a first run — it costs nothing, ignores everything else, and shows you the exact row shape. Switch it off before you expect real Quora data
  3. Give it something to work on — Search Keywords (searchQueries), Direct Quora URLs (directUrls), or both. Neither is flagged required, but a real run with neither exits immediately
  4. Set Maximum Results (maxResults) — read the note in the Input section first, because this is a per-keyword and per-question budget, not a run total
  5. Optionally paste a Webhook URL (webhookUrl) to have every row POSTed to your endpoint as it is written, and tune Max Concurrency, Request Delay and Browser Fallback
  6. Click Start and watch rows land live in the Output tab
  7. Export as JSON, CSV or Excel, or read the dataset through the Apify API

The Output tab has a view dropdown with six tables — Overview (All), Questions, Answers, Profiles, Topics and Spaces — so each content type is readable without filtering by hand.

How to scale to bulk Quora extraction

Both input fields are lists, so bulk is the normal mode. searchQueries takes any number of keywords and directUrls takes any number of Quora URLs, one per line; a single run processes every keyword first, then the direct URLs, and inside each of those two phases the targets are scraped concurrently up to maxConcurrency. Entries in directUrls may be plain strings or { "url": "..." } objects, so output from another tool can usually be fed in unchanged.

Budget carefully, because maxResults multiplies. It is the URL limit for each keyword and the answer limit for each question, so one keyword with maxResults: 50 can discover 50 URLs and pull up to 50 answers from each of them. Lower it, or split large jobs across runs, rather than assuming it caps the run.

What can you do with Quora question and answer data?

  • 🔍 A content strategist planning a topic cluster runs five seed keywords, then ranks rows by follow_count and answer_count to find the questions an audience actually follows rather than the ones that merely exist.
  • 📬 A data engineer running a scheduled Quora feed sets webhookUrl to an internal collector so each row lands in the warehouse as it is scraped, and keys the upsert on url and scrape_timestamp instead of polling the dataset after the run.
  • 📊 A market researcher studying how buyers describe a problem collects answer_text across a product category and filters is_ai_answer to false so machine-written filler never enters the sample.
  • 👤 A partnerships lead vetting subject-matter experts pastes profile URLs into directUrls and screens credentials, total_views and answer_count to find people with real depth before reaching out.
  • 🤖 An AI engineer building a question-answering agent indexes answer_text with title, topics and upvotes as metadata into a vector store, so the agent can answer "what do experienced practitioners actually say about this" from live Q&A rather than a stale export.

Every one of these is callable from an agent framework over the Apify API, since the Actor is a standard HTTP-triggered run.

How does Quora Scraper — Webhook Delivery & Demo Mode handle rate limits and blocking?

Egress runs on a proxy escalation ladder that starts at the cheapest rung. Every run begins on a direct connection with no proxy at all. Only when Quora pushes back does the Actor climb: direct → Apify datacenter → Apify residential, logging each switch, and it sticks on the higher rung for the rest of the run once it has escalated. Each target keeps its own sticky session id, so one target holds one exit IP.

Requests go out through curl_cffi impersonating Chrome 131, with a 40-second timeout and the delay set by requestDelay plus up to 0.3 seconds of jitter before each fetch. A response only counts as success if it is HTTP 200, contains ansFrontendGlobals, and carries a content node with real fields — a challenge shell that returns 200 with an empty stub is treated as a block, not as an empty page. Each exit IP gets up to three attempts with roughly a 1.2-second pause between them, because Quora often serves real data only on the second request to a session.

If the whole ladder fails, the Actor rotates through up to six further fresh residential exit IPs with exponential backoff capped at 6 seconds. Only then does the headless-browser fallback engage, if useBrowserFallback is on: a Chromium context per attempt, up to three attempts on fresh residential IPs, each waiting for network idle with a 60-second navigation timeout.

There is no CAPTCHA solving in this Actor, and none is claimed. If a page is still blocked after every attempt, the failure is logged and the run moves on — you get fewer rows for that URL, not a failed run and not an error row in the dataset.

⬇️ Input

Nine parameters, none of them flagged required by the schema. For a real run supply at least one of searchQueries or directUrls; for a free format preview, demoMode alone is enough.

ParameterRequiredTypeDescriptionExample Value
searchQueriesNoarrayKeywords to search on Quora. Each keyword is resolved to relevant Quora URLs and scraped automatically. Leave empty to only use direct URLs. Prefilled with ["python programming"].["what is python used for", "best python web framework"]
directUrlsNoarrayQuora URLs to scrape in bulk — questions, profiles (/profile/...), topics (/topic/...) or spaces (/q/...). Prefilled with one example question URL.["https://www.quora.com/What-is-Python-used-for", "https://www.quora.com/profile/Guido-van-Rossum-1"]
maxResultsNointegerMax results per search keyword, and max answers scraped per question URL. Minimum 1, maximum 50000. Default 50, Console prefill 10.25
demoModeNobooleanOn: emit sample rows without scraping and without charging. Off: real scraping. Default false.false
webhookUrlNostringOptional endpoint that receives each scraped row via HTTP POST (JSON body) the moment it is produced. Leave empty to skip. Default ""."https://example.com/hooks/quora"
maxConcurrencyNointegerHow many Quora pages to process in parallel. Minimum 1, maximum 20. Schema default 5.10
requestDelayNonumberPolite delay in seconds added before each page request. Minimum 0, maximum 30. Default 0.5.1.0
useBrowserFallbackNobooleanOn: render hard-blocked pages in a headless browser as a last resort. Off: fail fast on hard-blocked pages. Default true.true
proxyConfigurationNoobjectProxy settings. The scraper starts direct and only escalates to datacenter, then residential, if Quora blocks the request. Prefilled {"useApifyProxy": true}.{"useApifyProxy": true, "apifyProxyCountry": "US"}

Eight honest notes on how these actually behave:

  • ⚠️ webhookUrl is not declared as a secret field. It is a plain textfield in the schema, so its value is stored and displayed like any other input and is visible to anyone who can view the run — collaborators on the account, anyone the run or its input is shared with, and any API call that reads the run's input. Webhook URLs routinely embed a token in the path or query string, and such a token is exactly what an endpoint uses to decide a POST is genuine. Anyone who reads it can post forged rows to your endpoint. Treat a URL used here as disclosed: prefer an endpoint that authenticates the payload some other way, and rotate the URL if the run is shared.
  • demoMode overrides everything else. When it is on, the Actor emits its six sample rows and returns before any scraping code is reached. searchQueries, directUrls, maxResults, maxConcurrency, requestDelay, useBrowserFallback and proxyConfiguration are all ignored. The only inputs that survive are the first entry of searchQueries and the first entry of directUrls, which are copied into the sample rows' source_query and source_url — so a demo row can carry a real URL you supplied while every other value in it is invented. With both left empty those two fields fall back to the hard-coded python programming and a hard-coded Quora question URL.
  • maxResults is a per-target budget, not a run total. It caps the URLs discovered per keyword and the answers pulled per question page, and question rows are pushed on top of the answer count. Two keywords at maxResults: 50 is a ceiling in the thousands of charged rows, not 50 or 100. The schema default is 50 while the Console prefill is 10, so an API call that omits the field — or sends 0 or null — targets 50 per keyword, not 10. The 1–50000 range is this Actor's own cap, not Quora's.
  • maxConcurrency has a different default in the code. The schema says 5 and the Console prefills 5, but when the field is absent from the input entirely the code falls back to 6. It is then clamped to 1–20 whatever you send. The parallelism applies within a phase — all of a keyword's discovered URLs run together, then all direct URLs run together.
  • concurrency is accepted but undocumented. The code reads a concurrency field as an alias for maxConcurrency if maxConcurrency is absent. It is not in the schema, so the Console will not show it; it exists so inputs written for the base Actor still work.
  • requestDelay applies to page GETs only. It is added before each page fetch, along with up to 0.3 seconds of random jitter. The GraphQL answer-pagination POSTs and the webhook POSTs are not delayed by it, so raising it slows discovery and page loads but not answer paging.
  • proxyConfiguration is read far more narrowly than it looks. Only two keys are used: useApifyProxy, where false disables the ladder entirely and pins the run to direct connections, and apifyProxyCountry, which is applied to the residential rung only. apifyProxyGroups is ignored — the datacenter rung is always built as {"useApifyProxy": true} and the residential rung always uses the RESIDENTIAL group. Selecting residential in the Console does not make the run start on residential; it always starts direct.
  • Non-Quora URLs are not rejected. directUrls entries are classified by path only: /profile/, /topic/ and /q/ map to profile, topic and space, and everything else — including a URL on another domain — is treated as a question page. It will be fetched, validated, escalated up the proxy ladder, possibly rendered in a browser, and finally abandoned with a log line and no row.

Example input

{
"searchQueries": [
"what is python used for",
"best python web framework"
],
"directUrls": [
"https://www.quora.com/What-is-Python-used-for",
"https://www.quora.com/profile/Guido-van-Rossum-1",
"https://www.quora.com/topic/Python-programming-language",
"https://www.quora.com/q/datascience"
],
"maxResults": 25,
"demoMode": false,
"webhookUrl": "https://example.com/hooks/quora",
"maxConcurrency": 8,
"requestDelay": 0.8,
"useBrowserFallback": true,
"proxyConfiguration": {
"useApifyProxy": true,
"apifyProxyCountry": "US"
}
}

An input of {} is legal and does nothing. With demoMode off and both lists empty, the run logs No search keywords and no URLs provided — nothing to do. and exits immediately: zero rows, zero charge, and no silent fallback to a default keyword. Pressing Start in the Console without editing anything is a different matter — the prefills supply one keyword and one URL, so that run scrapes and charges.

⬆️ Output

Typed, normalized JSON with a stable shape per content_type across runs. Rows are pushed live as each page is parsed, so the dataset fills while the run is still going. Export as JSON, CSV or Excel, or read the dataset through the Apify API.

Because five row types share one dataset, the shape is sparse by design: an answer row carries 18 keys, a profile row 14, a space row 10, and question and topic rows 9 each. Keys that do not apply to a row type are omitted, not set to null, so use a presence check (row.get("upvotes")) rather than assuming a key exists. Keys that do apply can still hold null when Quora's payload omits the underlying counter — answer_count, follow_count, upvotes, comments_count, shares_count, follower_count, following_count, question_count, total_views, post_count, contributor_count and profile_image_url are all passed through unchanged.

Every row in a real run is charged, and there are no free rows to filter out. Each pushed row bills one row_result event. This Actor writes no header rows, no diagnostic rows and no accounting rows, so there is no errorReason, status, isError, isDiagnostic, type, rowType, fetchOutcome, success or charged marker field to look for and no filter expression to apply — failures appear in the run log only. A run that collects nothing pushes nothing and therefore charges nothing. The one exception is Demo Mode, where the entire dataset is sample rows pushed with no charge event attached; those rows carry no marker either, so the only way to know a dataset is a demo dataset is to know how the run was configured. The Actor also stops issuing charges for the rest of a run once Apify reports the run's charge limit reached, logging Charge limit reached — will stop charging.

Deduplication is narrow. Discovered URLs are deduplicated within a single keyword, not across keywords and not against directUrls, so two keywords that surface the same question scrape it twice and it appears twice. Answers are deduplicated by Quora's own answer id within one question page. Deduplicate on url yourself if a run mixes keywords and URLs.

The only filter most pipelines need is a split by type:

answers = [r for r in items if r["content_type"] == "answer"]

Example output

An answer row — the type most runs are mostly made of:

{
"content_type": "answer",
"title": "What is Python primarily used for?",
"url": "https://www.quora.com/What-is-Python-primarily-used-for/answer/Ravi-Chandran-88",
"answer_text": "Python earns its keep in four places, and they barely overlap:\nData work: pandas, NumPy and scikit-learn are the default toolkit in most analytics teams.\nBackend services: Django and FastAPI run a large share of the APIs you use daily.\nAutomation and glue: anything that has to talk to three systems at once.\nTeaching: the syntax gets out of the way while people learn to think.\nWhere it struggles is anything latency-critical or memory-bound.",
"answer_url": "https://www.quora.com/What-is-Python-primarily-used-for/answer/Ravi-Chandran-88",
"author_name": "Ravi Chandran",
"author_url": "https://www.quora.com/profile/Ravi-Chandran-88",
"author_credentials": "Backend engineer, 12 years writing Python in production",
"upvotes": 1847,
"comments_count": 63,
"shares_count": 21,
"answer_timestamp": "2y",
"is_ai_answer": false,
"question_title": "What is Python primarily used for?",
"question_url": "https://www.quora.com/What-is-Python-primarily-used-for",
"source_url": "https://www.quora.com/What-is-Python-primarily-used-for",
"source_query": "what is python used for",
"scrape_timestamp": "2026-07-25T09:14:02.481230+00:00"
}

The question row that preceded it:

{
"content_type": "question",
"title": "What is Python primarily used for?",
"url": "https://www.quora.com/What-is-Python-primarily-used-for",
"answer_count": 214,
"follow_count": 1396,
"topics": ["Python (programming language)", "Software Development", "Computer Programming"],
"source_url": "https://www.quora.com/What-is-Python-primarily-used-for",
"source_query": "what is python used for",
"scrape_timestamp": "2026-07-25T09:13:58.902847+00:00"
}

A profile row from a direct URL — note that source_query is absent, not empty:

{
"content_type": "profile",
"title": "Guido van Rossum",
"name": "Guido van Rossum",
"url": "https://www.quora.com/profile/Guido-van-Rossum-1",
"bio": "Creator of Python. Distinguished Engineer at Microsoft.",
"credentials": "Created the Python programming language",
"profile_image_url": "https://qph.cf2.quoracdn.net/main-thumb-1042118-200-oqkfmzwjxvbpqhtnrwdlkzcgeuysinat.jpeg",
"follower_count": 148203,
"following_count": 37,
"answer_count": 412,
"question_count": 19,
"total_views": 41738522,
"source_url": "https://www.quora.com/profile/Guido-van-Rossum-1",
"scrape_timestamp": "2026-07-25T09:16:44.113905+00:00"
}

A space row, showing the two keys unique to that type:

{
"content_type": "space",
"title": "Data Science",
"name": "Data Science",
"url": "https://www.quora.com/q/datascience",
"description": "A space for practitioners to share applied machine learning and analytics work.",
"follower_count": 104318,
"post_count": 8921,
"contributor_count": 2740,
"source_url": "https://www.quora.com/q/datascience",
"scrape_timestamp": "2026-07-25T09:17:12.660428+00:00"
}

And a topic row, the shortest shape in the dataset:

{
"content_type": "topic",
"title": "Python (programming language)",
"name": "Python (programming language)",
"url": "https://www.quora.com/topic/Python-programming-language",
"description": "Questions about the Python programming language, its libraries and its ecosystem.",
"follower_count": 1604882,
"question_count": 122480,
"source_url": "https://www.quora.com/topic/Python-programming-language",
"scrape_timestamp": "2026-07-25T09:17:39.204815+00:00"
}

What Demo Mode actually returns

Set demoMode to true and this is the dataset — six rows, every value below hard-coded in the source, no Quora request made. One of the two answer rows is reproduced in full so you can recognise it on sight:

{
"content_type": "answer",
"title": "What is Python primarily used for?",
"url": "https://www.quora.com/What-is-Python-primarily-used-for/answer/Sample-Human-Author",
"answer_text": "Python is a general-purpose language used for web development, data science, automation and AI. This is SAMPLE demo data — no scraping was performed.",
"answer_url": "https://www.quora.com/What-is-Python-primarily-used-for/answer/Sample-Human-Author",
"author_name": "Sample Human Author",
"author_url": "https://www.quora.com/profile/Sample-Human-Author",
"author_credentials": "Senior Software Engineer",
"upvotes": 2400,
"comments_count": 37,
"shares_count": 58,
"answer_timestamp": "3y",
"is_ai_answer": false,
"question_title": "What is Python primarily used for?",
"question_url": "https://www.quora.com/What-is-Python-primarily-used-for",
"source_url": "https://www.quora.com/What-is-Python-primarily-used-for",
"source_query": "python programming",
"scrape_timestamp": "2026-07-25T09:20:11.004512+00:00"
}

The other five are a question row for the same invented question, a second answer row attributed to Quora Assistant with is_ai_answer set to true, a profile row for Sample Human Author, a topic row for Python (programming language) and a space row for Python Programmers. scrape_timestamp is a genuine timestamp — the moment the demo row was generated. source_query and source_url echo your first keyword and first URL if you supplied any. Everything else, including every count, is a literal from the source file.

How does it work?

Quora ships its data as GraphQL payloads embedded in the page rather than as readable markup, so the Actor fetches pages with a Chrome-impersonating HTTP client and parses those payloads directly instead of matching CSS selectors. Each response is validated before it is trusted: it must be HTTP 200, contain Quora's front-end globals, and carry a content node with real fields, which is how throttle and challenge shells are told apart from genuine pages.

For a keyword, Quora URLs are discovered through DuckDuckGo with a site:quora.com filter and paginated until the limit is met or the engine stops returning new results. For a question page, the answers are then paged through Quora's own QuestionPagedListPaginationQuery in batches of up to 20 over the same sticky exit IP. Requests start on a direct connection and escalate to Apify datacenter and then residential proxies only when Quora pushes back, with a headless Chromium last resort for pages that stay blocked.

Answer bodies, bios and descriptions arrive as rich-text documents and are flattened to plain text. Because the data comes from those structured payloads rather than from the visual layout, a Quora front-end redesign does not change your field names. Only publicly visible data is collected — no account, cookie or session is used.

Integrations

The Actor is an Apify Actor, so it works with anything that can call the Apify API or consume a dataset — and, uniquely for this variant, with anything that can accept an HTTP POST.

Calling the scraper from Python

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("<YOUR_USERNAME>/quora-scraper-webhook-delivery-demo-mode").call(run_input={
"searchQueries": ["what is python used for"],
"directUrls": ["https://www.quora.com/profile/Guido-van-Rossum-1"],
"maxResults": 25,
"demoMode": False,
"proxyConfiguration": {"useApifyProxy": True},
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
if row["content_type"] == "answer":
print(row["upvotes"], row["author_name"], row["answer_timestamp"], row["answer_url"])

Works in Go, Ruby, Node.js, cURL — any language that can make an HTTP request. Branch on content_type to route each row type to the right handler.

Streaming every row to your own endpoint with webhookUrl

Set webhookUrl and the Actor becomes a push source. Here is exactly what happens, with nothing left implied:

  • What is sent. One complete dataset row per request, as the JSON body — the same object, key for key, that was just written to the dataset. There is no envelope, no batching, no run summary and no run-finished ping. Six rows means six POSTs.
  • When. Immediately after each row is pushed to the dataset, inside the same step that produced it. Delivery is awaited, so a slow endpoint slows that scraping task down.
  • Headers. Content-Type: application/json, plus the browser-impersonation headers the HTTP client sends. There is no signature, HMAC, bearer token or shared-secret header — the Actor sends nothing your endpoint can use to prove the POST came from this run. Authenticate at the URL level, or accept that you cannot verify the sender.
  • Failures. Up to three attempts per row. Connection errors, HTTP 429 and any 5xx are retried with exponential backoff between attempts; every other 4xx is treated as permanent and abandoned after the first try. Each attempt is bounded by a 15-second timeout. Neither the timeout nor the retry count is exposed in the input schema.
  • Blast radius of a failure. None on your data. The row is written to the dataset before it is sent, so a webhook failure never costs you a row, never marks the row, and never fails the run — it logs a warning and the scrape continues. At the end of the run the log prints a delivered / failed tally. If your endpoint was down, the dataset is still complete and is still the source of truth; re-drive it from there.
  • Demo Mode rows are POSTed too. Sample rows go through the same path as real rows, which is what makes Demo Mode useful for testing an integration — and dangerous if the receiving system stores what it gets without knowing the run was a demo.
  • No URL validation. Any non-empty string is used as-is. A typo does not fail the run; it produces one logged delivery failure per row.

No-code tools (n8n, Make, LangChain)

In n8n, point webhookUrl at an n8n Webhook node and the workflow fires once per scraped row with no polling at all; a Switch node on content_type then splits answers, questions and profiles into separate branches. In Make, either use the Apify module's run-and-wait for a batch pull, or create a custom webhook and paste its URL into webhookUrl for row-by-row delivery. In LangChain, wrap the Apify run endpoint as a tool and hand answer_text straight to the model, since it arrives as flat plain text. Apify schedules handle recurrence, so a weekly Quora feed into your own collector needs no code of your own.

Scraping publicly accessible pages is broadly treated as permissible where no authentication is bypassed, and this Actor reads only what a logged-out visitor sees — no account, no cookie, no session.

The regime that applies most directly here is contractual and copyright-based. Quora's terms of service govern automated access to and reuse of its site, and the substance of what you collect — answer_text, title / question_title, bio and description — is user-generated writing that its authors own. Reading it for research is a different proposition from republishing it, and republishing collected answer text as your own content or as a competing corpus is where the real exposure sits.

A narrower personal-data question attaches to the author-identity fields, because some of what this Actor returns identifies real people. On answer rows that is author_name, author_url and author_credentials. On profile rows it is title, name, url, bio, credentials, profile_image_url, follower_count, following_count, answer_count, question_count and total_views. Under GDPR and CCPA you need a lawful basis before you store or reuse those specific fields, and data minimisation applies — if your use case is content research, drop the author columns at ingestion and keep the text. question, topic and space rows carry no author identity at all.

One point specific to this variant: setting webhookUrl sends scraped rows, including those author-identity fields, to an external endpoint of your choosing. That is an outbound transfer of data that you control and are responsible for accounting for — the destination, its jurisdiction and its retention are your decisions, not the Actor's.

Consult legal counsel if your use case involves bulk storage of personal data, or republication of collected answer text.

❓ Frequently asked questions

What Quora fields does this scraper return?

The five most used are answer_text, upvotes, author_name, title and answer_timestamp. Every row also carries content_type, url, source_url and scrape_timestamp. Across the five row types the Actor writes 32 distinct keys — see the data fields table above for all of them.

Is Demo Mode real Quora data?

No. Demo Mode returns six rows of fabricated sample data hard-coded in the Actor's source. No Quora page is requested, no search is run, and the counts, names, bios and answer text are invented — several of them say SAMPLE demo data inside the text, and the author names are Sample Human Author and Quora Assistant. What it is genuinely useful for is the shape: the rows use exactly the same keys and types as real rows, so a demo run validates your parsing, your dataset views and your webhook receiver for free. Demo rows are pushed with no charge event attached. They carry no synthetic-data flag, so label a demo dataset yourself before anyone downstream mistakes it for Quora content.

What exactly does the webhook send, and when?

One dataset row per POST, as the JSON body, immediately after that row is written to the dataset. No batching, no summary payload, no run-finished ping. The only header the Actor sets is Content-Type: application/json — there is no signature or shared secret, so your endpoint cannot verify the sender from the request alone. Failed deliveries retry up to three times on connection errors, 429 and 5xx, give up immediately on other 4xx, and never stop the run or affect the dataset.

Does this scraper require a Quora account, login or cookies?

No. The Actor holds no session at any point — no username, no password, no cookie export. It reads the same logged-out pages any visitor sees. The only credential involved is your Apify token, and only if you call it through the API rather than the Console.

How many results can I extract in one run?

maxResults accepts 1 to 50000, but read it carefully: it is applied per keyword and per question, not per run. One keyword at maxResults: 25 discovers up to 25 Quora URLs and pulls up to 25 answers from each question among them, plus one question row each. Answers are paged in batches of up to 20 and stop when Quora reports no next page. Whether you reach the number depends on the target — a question with 9 answers yields 9 regardless of your setting.

What happens if a keyword returns zero results?

The run finishes normally and pushes nothing for that keyword. Discovery goes through DuckDuckGo, and if the search endpoint returns nothing usable — or returns its anomalyDetectionBlock marker for a flagged exit IP — the Actor logs Search engine did not return results for <keyword> (IP likely flagged). and moves to the next keyword. A run that ends with zero rows overall logs No rows collected. Try enabling the residential proxy or verify your URLs are public Quora pages. Because no diagnostic row is written and only real rows are charged, a zero-result run leaves you an empty dataset and no charge — check the run log, not the dataset, for the reason.

Can I scrape multiple Quora questions, keywords and URLs at once?

Yes. searchQueries and directUrls are both lists and can be used together in one run; keywords are processed first, then direct URLs, with up to maxConcurrency pages in flight inside each phase. Duplicate URLs are removed within a single keyword's discovery only — not across keywords and not against directUrls — so a question surfaced by two keywords is scraped and charged twice. Answers are deduplicated by Quora's own answer id within each question.

Does it work with Claude, ChatGPT and other AI agent tools?

Yes. It is callable as a standard HTTP-triggered run through the Apify API, so LangChain, CrewAI, n8n or a hand-written tool definition can invoke it and receive typed JSON with no parsing step. Have the agent branch on content_type and everything it sees is already flat. For agent workflows that prefer push over poll, webhookUrl delivers each row to your own collector as it is produced.

How does this compare to other Quora scrapers?

Checked on the Apify Store on 25 July 2026: fatihtahta/quora-scraper documents keyword search with searchType and timeFilter filters this Actor does not have, plus startUrls and a maxItemsPerQuery with a documented minimum of 10; its output is nested rather than flat — crawl metadata under source_context and details under question, answer, post, profile, space and topic objects — and its README states it writes no-result records carrying a status object, so its dataset does contain rows that are not content. crawlerbros/quora-scraper describes the same five content types with keyword and direct-URL input on its listing. alizarin_refrigerator-owner/quora-research describes questions, answers, topics and user profiles with engagement metrics on its listing. None of the three documents per-row webhook delivery on its listing.

What this Actor documents explicitly against that field: a flat one-level row shape, per-row webhook delivery to your own endpoint, a free Demo Mode preview, a direct-first proxy ladder, and a dataset that contains content rows only.

Does it return data in a format LLMs can use directly?

Yes. Typed, normalized JSON with consistent field names across runs and rich-text documents already flattened to plain text. No HTML parsing, no selectors. Pass a row directly into an LLM, index it into a vector store, or hand it to an agent tool — just remember that a demo-mode dataset is synthetic text and should never be indexed as Quora content.

What happens when Quora changes its layout or anti-bot system?

The scraper is maintained, and because it reads Quora's embedded GraphQL payloads rather than CSS selectors, a front-end redesign generally does not affect the field names you consume. If Quora's anti-bot posture tightens, the proxy ladder and the headless-browser fallback absorb it on your side without an input change. Your field names and types stay the same.

Can I use it without managing proxies or browser infrastructure?

Yes. The HTTP fingerprinting, the proxy ladder and the optional headless Chromium are all handled for you — direct, then Apify datacenter, then Apify residential, sticky once escalated, with six extra fresh residential exit IPs before the browser fallback engages. You never create a proxy account, rotate an IP or run a Chromium instance yourself. The Actor does not solve CAPTCHAs, and it makes no claim to.

Which Quora fields work best for AI training data and RAG indexing?

For RAG indexing: answer_text carries by far the most information per record and chunks cleanly, with title and topics as ready-made metadata filters and url as the citation. For training data: upvotes, comments_count, shares_count, answer_count, follow_count and is_ai_answer are the most structurally consistent fields across records. All values return as typed primitives or plain arrays, so no normalization pass is needed — just remember that counters can be null when Quora omits them, that keys not belonging to a row type are absent rather than null, and that filtering is_ai_answer to false keeps machine-written text out of a human-language corpus.

Scraper NameWhat it extracts
Quora Search ScraperThe same five Quora content types with a global result budget and absolute answer dates
Reddit Posts Scraper By Keyword & Score FilterReddit posts for a keyword, filtered by score
Reddit User Profile Posts And Comments Scraper With Account AgeA Reddit user's posts and comments with account age and karma stats
YouTube Search ScraperVideos, channels and playlists for a search term
X (Twitter) Posts SearchPublic posts matching a search query
Google News Scraper By Publisher & Site FilterNews articles filtered by publisher and site

💬 Your feedback

Found a bug, or need a field that is in Quora's payload but not in the output? Open an issue on the Actor's Issues tab. Reports that include the exact input JSON and the keyword or Quora URL you ran are the fastest to reproduce and fix — and if the report is about webhookUrl, redact the URL before you paste it.