> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thehog.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Build Social Listening Workflows for X

> Use X keyword and profile monitors to track hot topics, competitors, executive posts, and new conversation opportunities.

Use monitors when you want a topic-based job that runs on a schedule. Use search when you want a one-off snapshot before creating a recurring monitor.

This guide shows examples for social media teams that want to find relevant conversations early, watch competitors, and track what executives or target accounts post on X.

## What you can build

| Workflow                         | API pattern                   | Example                                                                          |
| -------------------------------- | ----------------------------- | -------------------------------------------------------------------------------- |
| Track hot topics                 | `x_keyword` monitor           | New posts mentioning your category, feature, launch, or pain point               |
| Monitor competitors              | `x_keyword` monitor           | Mentions of competitor names, pricing, launches, outages, or customer complaints |
| Watch company leaders            | `x_profile` monitor           | New posts from a CEO, founder, product leader, or analyst                        |
| Find conversation opportunities  | `x_keyword` search or monitor | Posts where people are asking for tools, recommendations, or alternatives        |
| Build a lightweight social inbox | monitor events polling        | Store new matching posts, dedupe by URL, and route them to Slack or your CRM     |

<Info>
  X keyword and profile monitors return matching posts, author usernames, post URLs, timestamps, and engagement counts when available. If you need a complete list of users who liked, reposted, or replied to a specific X post, treat that as a separate engagement expansion workflow rather than assuming every engagement identity is included in keyword monitor results.
</Info>

## Create X monitors

Create separate monitors for each workflow so you can route and score results differently.

<CodeGroup>
  ```bash Hot topic monitor theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://developer.thehog.ai/api/v1/monitors \
    -H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
    -H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "X: customer data platform conversations",
      "type": "x_keyword",
      "config": {
        "query": "\"customer data platform\" OR \"CDP\""
      },
      "cadence_minutes": 60,
      "max_results": 25
    }'
  ```

  ```bash Competitor monitor theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://developer.thehog.ai/api/v1/monitors \
    -H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
    -H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "X: competitor pricing and complaints",
      "type": "x_keyword",
      "config": {
        "query": "(\"Competitor A\" OR \"Competitor B\") (pricing OR expensive OR outage OR alternative)"
      },
      "cadence_minutes": 60,
      "max_results": 25
    }'
  ```

  ```bash Executive profile monitor theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://developer.thehog.ai/api/v1/monitors \
    -H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
    -H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "X: CEO posts",
      "type": "x_profile",
      "config": {
        "username": "example_ceo"
      },
      "cadence_minutes": 60,
      "max_results": 10
    }'
  ```
</CodeGroup>

## Poll new events

After a monitor runs, poll its events endpoint. Store your last successful poll timestamp and pass it as `since` so you only process new items.

```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl "https://developer.thehog.ai/api/v1/monitors/mon_01hxyz/events?since=2024-01-01T00:00:00.000Z&limit=50" \
  -H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
  -H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx"
```

A typical social inbox stores:

| Field                        | Why it matters                              |
| ---------------------------- | ------------------------------------------- |
| `event_json.url`             | Link for the social team                    |
| `event_json.id`              | Source-native post ID to help dedupe        |
| `event_json.author_username` | X account to review                         |
| `event_json.text`            | Post text to score, summarize, or route     |
| `event_json.created_at`      | When the post was published, when available |
| `detected_at`                | When the monitor found the post             |

The exact `event_json` fields can vary by source, so write your ingestion to prefer stable fields and fall back gracefully.

## One-off X search before monitoring

Run a search first when you are testing query wording or building a prospect-facing demo.

```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/search \
  -H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
  -H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "x_keyword",
    "query": "\"product analytics\" \"need a tool\"",
    "max_results": 20
  }'
```

The response returns `202 Accepted` with a `poll_url`. Poll that URL until the search status is `succeeded`.

## JavaScript example: route new X posts

Create `x-social-listening.mjs`:

```js theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
const API_BASE_URL = process.env.HOG_API_BASE_URL ?? "https://developer.thehog.ai";
const ACCESS_KEY = process.env.HOG_API_ACCESS_KEY;
const SECRET_KEY = process.env.HOG_API_SECRET_KEY;

const monitorId = process.argv[2];
const since = process.argv[3] ?? new Date(Date.now() - 60 * 60 * 1000).toISOString();

if (!ACCESS_KEY || !SECRET_KEY) {
  throw new Error("Set HOG_API_ACCESS_KEY and HOG_API_SECRET_KEY");
}

if (!monitorId) {
  throw new Error("Usage: node x-social-listening.mjs <monitor-id> [since-iso]");
}

async function get(path) {
  const response = await fetch(`${API_BASE_URL}${path}`, {
    headers: {
      "X-Access-Key": ACCESS_KEY,
      "X-Secret-Key": SECRET_KEY,
    },
  });

  if (!response.ok) {
    const text = await response.text();
    throw new Error(`${path} failed with ${response.status}: ${text}`);
  }

  return response.json();
}

function pickPost(event) {
  const payload = event.event_json ?? {};
  return {
    detectedAt: event.detected_at,
    url: payload.post_url ?? payload.url,
    author: payload.author_username ?? payload.author ?? payload.author_name,
    text: payload.content ?? payload.text ?? payload.title,
  };
}

function score(post) {
  const text = (post.text ?? "").toLowerCase();
  const positiveIntent = ["alternative", "recommend", "need", "looking for"];
  const competitorRisk = ["expensive", "outage", "broken", "switching"];
  const tags = new Set();

  if (positiveIntent.some((term) => text.includes(term))) {
    tags.add("buying-intent");
  }

  if (competitorRisk.some((term) => text.includes(term))) {
    tags.add("competitor-signal");
  }

  return {
    ...post,
    tags: [...tags],
  };
}

const params = new URLSearchParams({ since, limit: "50" });
const response = await get(`/api/v1/monitors/${monitorId}/events?${params}`);
const posts = (response.data ?? []).map(pickPost).filter((post) => post.url || post.text);

console.log(JSON.stringify(posts.map(score), null, 2));
```

Run it:

```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
export HOG_API_ACCESS_KEY="ak_xxxxxxxxxxxxxxxx"
export HOG_API_SECRET_KEY="sk_xxxxxxxxxxxxxxxx"

node x-social-listening.mjs mon_01hxyz 2024-01-01T00:00:00.000Z
```

## Production pattern

<Steps>
  <Step title="Create narrow monitors">
    Use one monitor per topic, competitor, campaign, or executive account. Narrow monitors are easier to route and score.
  </Step>

  <Step title="Poll on the monitor cadence">
    Poll `GET /api/v1/monitors/:id` to check `last_run_at`, then fetch `GET /api/v1/monitors/:id/events?since=...`.
  </Step>

  <Step title="Dedupe by post URL">
    Store the post URL or source-native ID before routing to Slack, a queue, or a CRM task.
  </Step>

  <Step title="Score for actionability">
    Tag posts that mention buying intent, competitor pain, executive announcements, or urgent support issues.
  </Step>

  <Step title="Keep a human in the loop">
    Use the API to surface opportunities early, then let your social or sales team decide whether and how to join the conversation.
  </Step>
</Steps>
