Hashtags and Mentions Feature
Overview
Automatic extraction, storage, and suggestion system for hashtags and user mentions in social media posts. This feature helps users reuse popular hashtags and mentions without having to remember or search for them each time.
Features
1. Automatic Extraction
- Hashtags: Automatically extracts hashtags (e.g.,
#fashion,#handmade) from post captions - Mentions: Automatically extracts user mentions (e.g.,
@username) from post captions - Platform-Specific: Tracks usage per platform (Facebook, Instagram, Twitter)
- Real-Time: Extraction happens during post creation/update
2. Smart Storage
- Deduplication: Stores each unique hashtag/mention only once
- Usage Tracking: Counts how many times each hashtag/mention is used
- Last Used: Tracks when each hashtag/mention was last used
- Platform Association: Links hashtags/mentions to specific platforms
3. Intelligent Suggestions
- Autocomplete: Type-ahead suggestions as you type
- Popular: Shows most frequently used hashtags/mentions
- Recent: Shows recently used hashtags/mentions
- Platform-Filtered: Suggestions filtered by selected platform
Database Schema
Hashtag Model
{
id: string (primary key)
tag: string (searchable, without #)
platform: "facebook" | "instagram" | "twitter" | "all"
usage_count: number (default: 0)
last_used_at: datetime (nullable)
metadata: json (nullable)
}
Mention Model
{
id: string (primary key)
username: string (searchable, without @)
display_name: string (nullable)
platform: "facebook" | "instagram" | "twitter"
platform_user_id: string (nullable)
usage_count: number (default: 0)
last_used_at: datetime (nullable)
metadata: json (nullable)
}
API Endpoints
Get Hashtag Suggestions
GET /admin/socials/hashtags
Query Parameters:
q(string): Search queryplatform(string): facebook | instagram | twitter | alllimit(number): Number of results (default: 10)type(string): suggestions | popular | recent
Response:
{
"hashtags": [
{
"tag": "fashion",
"platform": "instagram",
"usage_count": 15,
"last_used_at": "2025-11-15T12:00:00Z"
}
]
}
Get Mention Suggestions
GET /admin/socials/mentions
Query Parameters:
q(string): Search queryplatform(string): facebook | instagram | twitterlimit(number): Number of results (default: 10)
Response:
{
"mentions": [
{
"username": "jaalyantra",
"display_name": "Jaal Yantra Textiles",
"platform": "instagram",
"usage_count": 8,
"last_used_at": "2025-11-15T12:00:00Z"
}
]
}
React Hooks
useHashtagSuggestions
import { useHashtagSuggestions } from "../../hooks/api/hashtags"
const { data, isLoading } = useHashtagSuggestions(
"fash", // query
"instagram", // platform (optional)
true // enabled (optional)
)
// data.hashtags = [{ tag: "fashion", ... }, { tag: "fashiondesign", ... }]
usePopularHashtags
import { usePopularHashtags } from "../../hooks/api/hashtags"
const { data } = usePopularHashtags(
"instagram", // platform (optional)
20 // limit (optional)
)
useRecentHashtags
import { useRecentHashtags } from "../../hooks/api/hashtags"
const { data } = useRecentHashtags(
"instagram", // platform (optional)
20 // limit (optional)
useMentionSuggestions
import { useMentionSuggestions } from "../../hooks/api/mentions"
const { data, isLoading } = useMentionSuggestions(
"jaal", // query
"instagram", // platform (optional)
true // enabled (optional)
)
Utility Functions
Extract Hashtags
import { extractHashtags } from "../utils/text-extraction"
const text = "Check out our #handmade #fashion collection!"
const hashtags = extractHashtags(text)
// Returns: ["handmade", "fashion"]
Extract Mentions
import { extractMentions } from "../utils/text-extraction"
const text = "Thanks @jaalyantra for the collaboration!"
const mentions = extractMentions(text)
// Returns: ["jaalyantra"]
Validate Hashtag
import { isValidHashtag } from "../utils/text-extraction"
isValidHashtag("#fashion") // true
isValidHashtag("#") // false
isValidHashtag("#a".repeat(101)) // false (too long)
Validate Mention
import { isValidMention } from "../utils/text-extraction"
isValidMention("@jaalyantra", "instagram") // true
isValidMention("@ab", "instagram") // false (too short)
isValidMention("@".repeat(31), "instagram") // false (too long)
Workflow Integration
The extraction happens automatically when creating or updating social posts:
// In create-social-post workflow
if (enriched.caption) {
extractHashtagsMentionsStep({
caption: enriched.caption,
platform_name: input.platform_name || "all",
})
}
This runs asynchronously and doesn't block post creation.
Platform-Specific Rules
Instagram
- Hashtags: 1-100 characters, alphanumeric + underscores
- Mentions: 1-30 characters, alphanumeric + underscores + dots
- Restrictions: Cannot start/end with dot, no consecutive dots
Twitter
- Hashtags: 1-100 characters, alphanumeric + underscores
- Mentions: 1-15 characters, alphanumeric + underscores only
Facebook
- Hashtags: 1-100 characters, alphanumeric + underscores
- Mentions: 5-50 characters, alphanumeric + underscores + dots
Usage Examples
Example 1: Create Post with Hashtags
const post = {
name: "New Collection",
caption: "Check out our #handmade #fashion #kashmir collection! 🧵",
platform_id: "instagram_platform_id"
}
// Hashtags automatically extracted and stored:
// - handmade
// - fashion
// - kashmir
Example 2: Get Suggestions While Typing
// User types "#fash"
const { data } = useHashtagSuggestions("#fash", "instagram")
// Returns suggestions:
// - fashion (used 15 times)
// - fashiondesign (used 8 times)
// - fashionista (used 3 times)
Example 3: Show Popular Hashtags
const { data } = usePopularHashtags("instagram", 10)
// Returns top 10 most used hashtags:
// - handmade (50 uses)
// - fashion (45 uses)
// - kashmir (40 uses)
// ...
UI Component Integration
Autocomplete Input (Future Enhancement)
import { useHashtagSuggestions } from "../../hooks/api/hashtags"
const HashtagInput = ({ value, onChange, platform }) => {
const [query, setQuery] = useState("")
const { data } = useHashtagSuggestions(query, platform)
return (
<Textarea
value={value}
onChange={(e) => {
onChange(e.target.value)
// Extract last word being typed
const words = e.target.value.split(/\s/)
const lastWord = words[words.length - 1]
if (lastWord.startsWith('#')) {
setQuery(lastWord)
}
}}
/>
{data?.hashtags && (
<SuggestionList>
{data.hashtags.map(h => (
<SuggestionItem onClick={() => insertHashtag(h.tag)}>
#{h.tag} ({h.usage_count} uses)
</SuggestionItem>
))}
</SuggestionList>
)}
)
}
Performance Considerations
- Async Extraction: Hashtag/mention extraction doesn't block post creation
- Debounced Suggestions: UI should debounce autocomplete queries
- Caching: React Query caches suggestions for better performance
- Indexing: Database indexes on
tagandusernamefields for fast lookups
Future Enhancements
- Trending Hashtags: Track trending hashtags over time periods
- Hashtag Analytics: Show performance metrics for each hashtag
- Mention Verification: Verify mentions against actual social media accounts
- Hashtag Groups: Create and save hashtag groups for quick insertion
- Smart Suggestions: ML-based suggestions based on post content
- Cross-Platform Sync: Sync hashtags across platforms
- Hashtag Research: Suggest related hashtags based on content
Testing
Unit Tests
describe("extractHashtags", () => {
it("should extract hashtags from text", () => {
const text = "Love #fashion and #design"
expect(extractHashtags(text)).toEqual(["fashion", "design"])
})
it("should handle Unicode hashtags", () => {
const text = "#नमस्ते #مرحبا"
expect(extractHashtags(text).length).toBe(2)
})
})
Integration Tests
describe("Hashtag Extraction Workflow", () => {
it("should extract and store hashtags on post creation", async () => {
const post = await createPost({
caption: "Test #hashtag",
platform_id: "test_platform"
})
const hashtags = await listHashtags({ tag: "hashtag" })
expect(hashtags.length).toBe(1)
expect(hashtags[0].usage_count).toBe(1)
})
})
Files Created
Models
/src/modules/socials/models/hashtag.ts/src/modules/socials/models/mention.ts
Services
/src/modules/socials/service.ts(updated)/src/modules/socials/utils/text-extraction.ts
Workflows
/src/workflows/socials/extract-hashtags-mentions.ts/src/workflows/socials/create-social-post.ts(updated)
API Routes
/src/api/admin/socials/hashtags/route.ts/src/api/admin/socials/mentions/route.ts
React Hooks
/src/admin/hooks/api/hashtags.ts/src/admin/hooks/api/mentions.ts
Migration Required
After implementing this feature, run database migrations to create the new tables:
npx medusa db:migrate
This will create:
hashtagtablementiontable