From xpoz
Compares brands and products across social media using Xpoz: share of voice, sentiment, positioning, and audience overlap. Useful for competitive analysis.
How this skill is triggered — by the user, by Claude, or both
Slash command
/xpoz:competitive-intelThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Compare multiple brands or products side by side across Twitter/X, Reddit, and Instagram. Measure share of voice, compare sentiment, identify positioning differences, and discover competitive advantages from real social conversations.
Compare multiple brands or products side by side across Twitter/X, Reddit, and Instagram. Measure share of voice, compare sentiment, identify positioning differences, and discover competitive advantages from real social conversations.
Activate when the user asks:
Before fetching data, ensure Xpoz access is configured. Follow these checks in order.
If you have MCP tools, try calling any Xpoz tool (e.g., checkAccessKeyStatus). If it works → skip to Step 1.
If you have the SDK, try:
from xpoz import XpozClient
client = XpozClient() # reads XPOZ_API_KEY env var
If this succeeds without error → skip to Step 1.
If neither works, you need to authenticate. Choose the path that fits your environment:
If mcporter is available:
mcporter call xpoz.checkAccessKeyStatus
If hasAccessKey: true → ready. If not:
mcporter config add xpoz https://mcp.xpoz.ai/mcp --auth oauth
Then authenticate — generate the OAuth URL and send it to the user:
Step 1: Generate authorization URL
import secrets, hashlib, base64, urllib.parse, json, urllib.request, os
verifier = secrets.token_urlsafe(64)
challenge = base64.urlsafe_b64encode(hashlib.sha256(verifier.encode()).digest()).rstrip(b'=').decode()
state = secrets.token_urlsafe(32)
# Dynamic client registration
reg_req = urllib.request.Request(
'https://mcp.xpoz.ai/oauth/register',
data=json.dumps({
'client_name': 'Agent Skills',
'redirect_uris': ['https://www.xpoz.ai/oauth/openclaw'],
'grant_types': ['authorization_code'],
'response_types': ['code'],
'token_endpoint_auth_method': 'none',
}).encode(),
headers={'Content-Type': 'application/json'},
)
reg_resp = json.loads(urllib.request.urlopen(reg_req).read())
params = urllib.parse.urlencode({
'response_type': 'code',
'client_id': reg_resp['client_id'],
'code_challenge': challenge,
'code_challenge_method': 'S256',
'redirect_uri': 'https://www.xpoz.ai/oauth/openclaw',
'state': state,
'scope': 'mcp:tools',
'resource': 'https://mcp.xpoz.ai/',
})
auth_url = 'https://mcp.xpoz.ai/oauth/authorize?' + params
# Save state for token exchange
os.makedirs(os.path.expanduser('~/.cache/xpoz-oauth'), exist_ok=True)
with open(os.path.expanduser('~/.cache/xpoz-oauth/state.json'), 'w') as f:
json.dump({'verifier': verifier, 'state': state, 'client_id': reg_resp['client_id'],
'redirect_uri': 'https://www.xpoz.ai/oauth/openclaw'}, f)
print(auth_url)
Step 2: Send the URL to the user
Tell them:
"I need to connect to Xpoz for social media data. Please open this link and sign in:
[auth_url]
After authorizing, you'll see a code. Paste it back to me here."
Step 3: WAIT for the user to reply with the code. Do not proceed until they respond.
Step 4: Exchange the code for a token
Once the user provides the code (either a raw code or a URL containing ?code=...), extract the code and exchange it:
import json, urllib.request, urllib.parse, subprocess, os
with open(os.path.expanduser('~/.cache/xpoz-oauth/state.json')) as f:
oauth = json.load(f)
code = "THE_CODE_FROM_USER" # Extract from user's reply
data = urllib.parse.urlencode({
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': oauth['redirect_uri'],
'client_id': oauth['client_id'],
'code_verifier': oauth['verifier'],
}).encode()
req = urllib.request.Request(
'https://mcp.xpoz.ai/oauth/token',
data=data,
headers={'Content-Type': 'application/x-www-form-urlencoded'},
)
resp = json.loads(urllib.request.urlopen(req).read())
token = resp['access_token']
# Configure mcporter with the token (token is never printed)
subprocess.run(['mcporter', 'config', 'remove', 'xpoz'], capture_output=True)
subprocess.run(['mcporter', 'config', 'add', 'xpoz', 'https://mcp.xpoz.ai/mcp',
'--header', f'Authorization=Bearer {token}'], check=True)
# Clean up
os.remove(os.path.expanduser('~/.cache/xpoz-oauth/state.json'))
print("Xpoz configured successfully")
Step 5: Verify with mcporter call xpoz.checkAccessKeyStatus → should return hasAccessKey: true.
For Claude Code users without mcporter, add to ~/.claude.json:
{
"mcpServers": {
"xpoz": {
"url": "https://mcp.xpoz.ai/mcp",
"transport": "http-stream"
}
}
}
Claude Code handles OAuth automatically on first tool call — the user just needs to authorize in their browser when prompted.
Ask the user:
"I need a Xpoz API key to access social media data. Please go to https://xpoz.ai/get-token (it's free, no credit card needed) and paste the key back to me."
WAIT for the user to reply with the key. Then:
Python:
pip install xpoz
from xpoz import XpozClient
client = XpozClient("THE_KEY_FROM_USER")
TypeScript:
npm install @xpoz/xpoz
import { XpozClient } from "@xpoz/xpoz";
const client = new XpozClient({ apiKey: "THE_KEY_FROM_USER" });
await client.connect();
Or set the environment variable and use the default constructor:
export XPOZ_API_KEY=THE_KEY_FROM_USER
| Problem | Solution |
|---|---|
| MCP: "Unauthorized" | Re-run the OAuth flow above |
SDK: AuthenticationError | Verify key at xpoz.ai/settings |
| Token exchange fails | Ask user to re-authorize — codes are single-use |
Extract:
Build expanded queries for each brand:
"Slack" → "Slack" NOT "cut some slack" NOT "slack off""Discord" → "Discord" NOT "sow discord" NOT "discord between"Run parallel searches — one per brand, per platform.
For each brand, call:
Twitter posts:
Call getTwitterPostsByKeywords:
query: "<brand query>"
fields: ["id", "text", "authorUsername", "createdAtDate", "likeCount", "retweetCount", "impressionCount"]
startDate: "<7 days ago>"
endDate: "<today>"
language: "en"
Twitter users discussing the brand:
Call getTwitterUsersByKeywords:
query: "<brand query>"
fields: ["id", "username", "name", "followersCount", "relevantTweetsCount", "relevantTweetsLikesSum"]
startDate: "<7 days ago>"
Reddit (for each brand):
Call getRedditPostsByKeywords:
query: "<brand query>"
fields: ["id", "title", "text", "score", "numComments", "subreddit", "createdAtDate"]
startDate: "<7 days ago>"
CRITICAL: Each call returns an operationId — poll checkOperationStatus until "completed".
Tip: Launch all brand searches in sequence, collect all operationIds, then poll them. This is faster than waiting for each one.
from xpoz import XpozClient
client = XpozClient()
brands = {
"Slack": '"Slack" NOT "cut some slack"',
"Discord": '"Discord" NOT "sow discord"',
"Teams": '"Microsoft Teams" OR "MS Teams"',
}
brand_data = {}
for brand_name, query in brands.items():
# Twitter posts
twitter = client.twitter.search_posts(
query,
start_date="2026-02-16",
end_date="2026-02-23",
language="en",
fields=["id", "text", "author_username", "like_count", "retweet_count", "impression_count", "created_at_date"]
)
# Twitter users (for influencer overlap analysis)
users = client.twitter.get_users_by_keywords(
query,
start_date="2026-02-16",
fields=["username", "followers_count", "relevant_tweets_count", "relevant_tweets_likes_sum"]
)
# Reddit posts
reddit = client.reddit.search_posts(
query,
start_date="2026-02-16",
fields=["id", "title", "text", "score", "num_comments", "subreddit", "created_at_date"]
)
brand_data[brand_name] = {
"twitter_posts": twitter,
"twitter_users": users,
"reddit_posts": reddit,
"tweet_count": twitter.pagination.total_rows,
"reddit_count": reddit.pagination.total_rows,
}
client.close()
import { XpozClient } from "@xpoz/xpoz";
const client = new XpozClient();
await client.connect();
const brands: Record<string, string> = {
Slack: '"Slack" NOT "cut some slack"',
Discord: '"Discord" NOT "sow discord"',
Teams: '"Microsoft Teams" OR "MS Teams"',
};
const brandData: Record<string, any> = {};
for (const [name, query] of Object.entries(brands)) {
const twitter = await client.twitter.searchPosts(query, {
startDate: "2026-02-16",
endDate: "2026-02-23",
language: "en",
fields: ["id", "text", "authorUsername", "likeCount", "retweetCount", "createdAtDate"],
});
const reddit = await client.reddit.searchPosts(query, {
startDate: "2026-02-16",
fields: ["id", "title", "text", "score", "numComments", "subreddit"],
});
brandData[name] = { twitter, reddit };
}
await client.close();
Share of Voice (SOV):
SOV for Brand A = (Brand A mentions) / (Total mentions across all brands) × 100
Calculate separately for Twitter and Reddit.
Sentiment Comparison: For each brand, classify posts into positive/neutral/negative (see social-sentiment-analyzer skill for classification method) and compare:
Engagement Comparison:
Audience Overlap:
Positioning Analysis:
## Competitive Intelligence: [BRAND] vs Competitors
**Period:** [date range] | **Platforms:** Twitter, Reddit
### Share of Voice
| Brand | Twitter Posts | Reddit Posts | Total | SOV |
|-------|-------------|-------------|-------|-----|
| Slack | 1,234 | 456 | 1,690 | 42% |
| Discord | 890 | 678 | 1,568 | 39% |
| Teams | 456 | 321 | 777 | 19% |
### Sentiment Comparison
| Brand | Score | Positive | Neutral | Negative | Trend |
|-------|-------|----------|---------|----------|-------|
| Slack | 62 | 38% | 42% | 20% | → Stable |
| Discord | 71 | 48% | 35% | 17% | ↑ Improving |
| Teams | 45 | 22% | 45% | 33% | ↓ Declining |
### Engagement Comparison
| Brand | Avg Likes (Twitter) | Avg Score (Reddit) | Avg Comments |
|-------|--------------------|--------------------|--------------|
| ... | ... | ... | ... |
### Key Findings
#### [Brand A] Strengths
- [What people praise, with example quotes]
#### [Brand A] Weaknesses
- [What people complain about, with example quotes]
#### [Brand B] Strengths / Weaknesses
...
### Competitive Positioning Map
- **[Brand A]:** Positioned as [description]
- **[Brand B]:** Positioned as [description]
- **Switching signals:** [users switching from X to Y, with reasons]
### Audience Overlap
[X users posted about multiple brands — analysis of their preferences]
### Recommendations
[3-5 actionable insights based on the competitive landscape]
npx claudepluginhub xpozpublic/xpoz-agent-skills --plugin xpozCalculates and tracks share of voice across organic search, paid search, social media, and AI engine citations. Useful for competitive visibility analysis and market share forecasting.
Monitors brand reputation and sentiment across Twitter/X, Reddit, Instagram, YouTube, and LinkedIn using the anysite MCP server. Tracks mentions, analyzes sentiment, and detects reputation risks.
Monitors brand, competitors, and industry trends across social media channels like Twitter/X, Reddit, TikTok, Instagram, and review platforms. Useful for early crisis detection and content opportunity discovery.