Files
dewemoji/dewemoji-ux-flow-brief.md
2026-02-12 00:52:40 +07:00

22 KiB
Executable File
Raw Blame History

Dewemoji User Flow & UX Brief

Version: 1.0
Date: February 8, 2026
Purpose: Define seamless user experience across visitor → logged → paid states
Related Doc: dewemoji-direction-2026.md


Executive Summary

Dewemoji implements a hybrid quick-add flow where Personal users can add keywords instantly from emoji detail pages (80% of use cases) while maintaining full CRUD power in the dashboard (20% management). This creates a frictionless progression: discovery → personalization → habit, without disrupting the free user experience.

Core UX Principle: "Add keywords where you discover emojis, manage them where you organize."


1. User State Definitions

1.1 Visitor (Non-Logged)

Who: Anyone landing on dewemoji.com or using Chrome extension (no account)
Intent: Quick emoji search and usage
Experience: Zero friction, no login walls

1.2 Free User (Logged, No Subscription)

Who: Registered account, free tier
Intent: Exploring Personal features, considering upgrade
Experience: Full free features + gentle upgrade hints

1.3 Personal User (Logged, Paid)

Who: Active Personal subscription ($4.99/mo, $49/yr, or $99 lifetime)
Intent: Building and syncing personal keyword library
Experience: Full personalization power across all touchpoints


2. Primary User Flows

2.1 Discovery Flow (All Users)

User lands on dewemoji.com
    ↓
Search bar: "bekicot"
    ↓
Results page: 🐌 snail (public keywords: "snail, escargot")
    ↓
Click emoji → Detail page
    ↓
[State-dependent experience - see Section 3]

Key Insight: All users start here. Free discovery hooks them; Personal lets them own it.


2.2 Personalization Flow (Personal Users)

Primary: Quick Add from Detail Page (80% Usage)

Personal user searches "snail"
    ↓
Detail page shows:
┌─────────────────────────────────────┐
│ 🐌 Snail                            │
│                                     │
│ Public Keywords: snail, escargot   │
│                                     │
│ Your Keywords: (none yet)          │
│ [+ Add Your Keyword]               │
└─────────────────────────────────────┘
    ↓
User clicks [+ Add Your Keyword]
    ↓
Inline modal appears:
┌─────────────────────────────────────┐
│ What do you call this emoji?       │
│ ┌─────────────────────────────────┐│
│ │ bekicot, siput                  ││
│ └─────────────────────────────────┘│
│ Language: [Indonesian ▾]           │
│ [Cancel]  [Save Keyword]           │
└─────────────────────────────────────┘
    ↓
Saves instantly → Toast: "Added 'bekicot' to your library ✓"
    ↓
Detail page now shows:
┌─────────────────────────────────────┐
│ 🐌 Snail                            │
│                                     │
│ Public Keywords: snail, escargot   │
│                                     │
│ Your Keywords:                      │
│ • bekicot (ID) [edit] [×]          │
│ • siput (ID) [edit] [×]            │
│ [+ Add Another]                    │
└─────────────────────────────────────┘
    ↓
Next search: "bekicot" → 🐌 appears in results!

Why This Flow:

  • Contextual: User is already looking at the emoji they want to name
  • Fast: 2 clicks (add button → save), ~5 seconds total
  • Immediate gratification: See change instantly in searches
  • Low friction: No navigation away from discovery flow

Secondary: Dashboard Management (20% Usage)

When Used:

  • Bulk editing/organizing keywords
  • Reviewing all keywords at once
  • Exporting/importing keyword libraries
  • Fixing typos across multiple entries
User navigates to Dashboard → My Keywords tab
    ↓
Table view:
┌───────────────────────────────────────────────────────────┐
│ Emoji | Your Keywords      | Lang | Actions              │
├───────────────────────────────────────────────────────────┤
│ 🐌    | bekicot, siput     | ID   | [Edit] [Delete]      │
│ 😊    | senyum, happy      | ID   | [Edit] [Delete]      │
│ 🔥    | api, fire, lit     | ID   | [Edit] [Delete]      │
└───────────────────────────────────────────────────────────┘
[+ Add Keyword] [Import JSON] [Export JSON] [Search/Filter]
    ↓
User clicks [+ Add Keyword]
    ↓
Modal: Search emoji picker → Select 🎉 → Add keywords
    ↓
Saves to table → Auto-sync to extension

Why Dashboard Exists:

  • Power users want bulk operations
  • Easy to review/audit entire library
  • Import/export for backup
  • Edit mistakes without finding emoji again

2.3 Upgrade Flow (Free → Personal)

Trigger Points

1. On Detail Page (Soft Prompt)

Free user on emoji detail page sees:
┌─────────────────────────────────────┐
│ 🐌 Snail                            │
│                                     │
│ Public Keywords: snail, escargot   │
│                                     │
│ 💎 Want to add your own keywords?  │
│    like 'bekicot' or 'siput'?      │
│    [Upgrade to Personal →]         │
└─────────────────────────────────────┘

2. On Search Miss (Strong Prompt)

User searches "bekicot" → No results
    ↓
Results page shows:
┌─────────────────────────────────────┐
│ No results for "bekicot"           │
│                                     │
│ 💡 With Personal, you can create   │
│    "bekicot → 🐌" and sync it      │
│    everywhere.                      │
│    [Try Personal Free for 7 Days]  │
└─────────────────────────────────────┘

3. From Extension (Contextual)

Extension user searches "bekicot" → Not found
    ↓
Extension shows inline banner:
"Add 'bekicot' to your library with Personal"
[Upgrade] button → Opens dewemoji.com/upgrade

4. From Dashboard (Clear Path)

Free user clicks "My Keywords" tab
    ↓
Shows empty state:
┌─────────────────────────────────────┐
│ 📚 Your Personal Keyword Library   │
│                                     │
│ You have 0 keywords.               │
│                                     │
│ Upgrade to Personal to:            │
│ ✓ Add unlimited keywords           │
│ ✓ Search in your language          │
│ ✓ Sync across all devices          │
│                                     │
│ [Start 7-Day Free Trial]           │
└─────────────────────────────────────┘

3. State-Dependent UI Elements

3.1 Emoji Detail Page

Visitor (Non-Logged)

<!-- Public info only -->
<div class="emoji-detail">
  <h1>🐌 Snail</h1>
  <section class="public-keywords">
    <h3>Keywords</h3>
    <ul>
      <li>snail</li>
      <li>escargot</li>
      <li>slow</li>
    </ul>
  </section>
  
  <div class="cta-banner">
    <p>💡 Want to search in your language?</p>
    <button>Sign Up Free</button>
  </div>
</div>

Free User (Logged)

<!-- Public info + muted personal section -->
<div class="emoji-detail">
  <h1>🐌 Snail</h1>
  
  <section class="public-keywords">
    <h3>Keywords</h3>
    <ul><li>snail</li><li>escargot</li></ul>
  </section>
  
  <section class="user-keywords muted">
    <h3>Your Keywords</h3>
    <div class="upgrade-overlay">
      <p>💎 Add personal keywords like 'bekicot'</p>
      <button class="upgrade-btn">Upgrade to Personal</button>
    </div>
  </section>
</div>

Personal User (Logged + Paid)

<!-- Full personalization active -->
<div class="emoji-detail">
  <h1>🐌 Snail</h1>
  
  <section class="public-keywords">
    <h3>Public Keywords</h3>
    <ul><li>snail</li><li>escargot</li><li>slow</li></ul>
  </section>
  
  <section class="user-keywords active">
    <h3>Your Keywords</h3>
    <ul class="keyword-list">
      <li>
        <span class="keyword">bekicot</span>
        <span class="lang-tag">ID</span>
        <button class="edit-btn">edit</button>
        <button class="delete-btn">×</button>
      </li>
      <li>
        <span class="keyword">siput</span>
        <span class="lang-tag">ID</span>
        <button class="edit-btn">edit</button>
        <button class="delete-btn">×</button>
      </li>
    </ul>
    <button class="add-keyword-btn">+ Add Keyword</button>
  </section>
</div>

<!-- Add Keyword Modal (hidden until clicked) -->
<dialog id="add-keyword-modal">
  <h3>What do you call this emoji?</h3>
  <input type="text" placeholder="Enter keywords (comma-separated)" />
  <select name="language">
    <option value="en">English</option>
    <option value="id">Indonesian</option>
    <option value="ko">Korean</option>
    <option value="ja">Japanese</option>
  </select>
  <div class="modal-actions">
    <button class="cancel">Cancel</button>
    <button class="save primary">Save Keyword</button>
  </div>
</dialog>

3.2 Search Results Page

All Users (Public Results)

<div class="search-results">
  <div class="emoji-card">
    <span class="emoji">🐌</span>
    <span class="name">Snail</span>
    <span class="matched-keyword">snail</span>
  </div>
</div>

Personal User (Blended Results)

<div class="search-results">
  <!-- Private keyword match (appears first) -->
  <div class="emoji-card user-match">
    <span class="emoji">🐌</span>
    <span class="name">Snail</span>
    <span class="matched-keyword">
      bekicot
      <span class="badge personal">Your keyword</span>
    </span>
    <button class="quick-edit">Edit</button>
  </div>
  
  <!-- Public keyword matches (below) -->
  <div class="emoji-card">
    <span class="emoji">🐌</span>
    <span class="name">Snail</span>
    <span class="matched-keyword">snail</span>
  </div>
</div>

3.3 Dashboard (Personal Users Only)

<div class="dashboard">
  <nav class="tabs">
    <button class="active">My Keywords</button>
    <button>API Keys</button>
    <button>Billing</button>
  </nav>
  
  <!-- My Keywords Tab -->
  <div class="tab-content" id="keywords">
    <div class="toolbar">
      <button class="primary">+ Add Keyword</button>
      <button>Import JSON</button>
      <button>Export JSON</button>
      <input type="search" placeholder="Search your keywords..." />
    </div>
    
    <table class="keyword-table">
      <thead>
        <tr>
          <th>Emoji</th>
          <th>Your Keywords</th>
          <th>Language</th>
          <th>Actions</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>🐌</td>
          <td>bekicot, siput</td>
          <td><span class="lang-tag">ID</span></td>
          <td>
            <button class="edit">Edit</button>
            <button class="delete">Delete</button>
          </td>
        </tr>
        <!-- More rows... -->
      </tbody>
    </table>
  </div>
</div>

4. API Endpoints for UX Flows

4.1 Detail Page Quick Add

Fetch user's keywords for specific emoji:

GET /v1/emoji/:slug?include_user_keywords=true
Authorization: Bearer dew_abc123...

Response:
{
  "emoji": {...},
  "public_keywords": ["snail", "escargot"],
  "user_keywords": [
    {"id": "uk_1", "keyword": "bekicot", "lang": "id"},
    {"id": "uk_2", "keyword": "siput", "lang": "id"}
  ]
}

Add keyword from detail page:

POST /v1/keywords/quick
Authorization: Bearer dew_abc123...

Body:
{
  "emoji_slug": "snail",
  "keywords": ["bekicot", "siput"],
  "lang": "id"
}

Response:
{
  "success": true,
  "added": ["bekicot", "siput"],
  "emoji_slug": "snail"
}

Edit single keyword:

PATCH /v1/keywords/:id
Authorization: Bearer dew_abc123...

Body:
{
  "keyword": "bekicot kecil"
}

Delete keyword:

DELETE /v1/keywords/:id
Authorization: Bearer dew_abc123...

4.2 Dashboard Bulk Operations

List all user keywords:

GET /v1/keywords?page=1&limit=50
Authorization: Bearer dew_abc123...

Response:
{
  "keywords": [
    {
      "id": "uk_1",
      "emoji_slug": "snail",
      "emoji": "🐌",
      "keyword": "bekicot",
      "lang": "id",
      "created_at": "2026-02-08T10:30:00Z"
    }
    // ... more
  ],
  "total": 47,
  "page": 1
}

Bulk import:

POST /v1/keywords/import
Authorization: Bearer dew_abc123...

Body:
{
  "keywords": [
    {"emoji_slug": "snail", "keywords": ["bekicot"], "lang": "id"},
    {"emoji_slug": "fire", "keywords": ["api"], "lang": "id"}
  ]
}

Response:
{
  "imported": 2,
  "skipped": 0,
  "errors": []
}

Export:

GET /v1/keywords/export?format=json
Authorization: Bearer dew_abc123...

Response: (Download JSON file)

5. Frontend Implementation Specs

5.1 Emoji Detail Page Changes

File: /pages/emoji/[slug].js (or equivalent)

Required Elements:

  1. User keywords section (Personal only)

    • Fetch on page load: GET /v1/emoji/:slug?include_user_keywords=true
    • Show list of user's keywords with edit/delete buttons
    • Show "Add Keyword" button
  2. Add keyword modal

    • Input: comma-separated keywords
    • Dropdown: language selector (EN, ID, KO, JA, etc.)
    • Save button → POST /v1/keywords/quick
    • Success → update UI without page reload
  3. Inline edit

    • Click "edit" → input becomes editable
    • Save → PATCH /v1/keywords/:id
    • Cancel → revert
  4. Inline delete

    • Click "×" → confirm modal
    • Yes → DELETE /v1/keywords/:id → remove from UI

State Management:

const [userKeywords, setUserKeywords] = useState([]);
const [isPersonal, setIsPersonal] = useState(false);

// On mount
useEffect(() => {
  if (user?.tier === 'personal') {
    fetchUserKeywords(emojiSlug);
  }
}, [emojiSlug, user]);

// Add keyword
const handleAddKeyword = async (keywords, lang) => {
  const result = await api.post('/keywords/quick', {
    emoji_slug: emojiSlug,
    keywords: keywords.split(',').map(k => k.trim()),
    lang
  });
  
  if (result.success) {
    fetchUserKeywords(emojiSlug); // Refresh list
    toast.success('Keywords added!');
  }
};

5.2 Dashboard Implementation

File: /pages/dashboard.js

Tabs:

  1. My Keywords (default)
  2. API Keys
  3. Billing

My Keywords Tab Components:

// Main table component
<KeywordTable 
  keywords={keywords}
  onEdit={handleEdit}
  onDelete={handleDelete}
  onSearch={handleSearch}
/>

// Toolbar actions
<Toolbar>
  <AddKeywordButton onClick={openModal} />
  <ImportButton />
  <ExportButton />
  <SearchInput onChange={handleSearch} />
</Toolbar>

// Add keyword modal (with emoji picker)
<AddKeywordModal
  onSave={handleAddKeyword}
  onCancel={closeModal}
/>

Features:

  • Pagination (50 per page)
  • Search/filter by keyword or emoji
  • Bulk select + delete
  • Sort by: date added, emoji name, language

5.3 Upgrade Flow Pages

File: /pages/upgrade.js or /pages/pricing.js

Components:

  1. Feature comparison table

    <table class="pricing-comparison">
      <tr>
        <th>Feature</th>
        <th>Free</th>
        <th>Personal</th>
      </tr>
      <tr>
        <td>Public emoji search</td>
        <td>✅ Unlimited</td>
        <td>✅ Unlimited</td>
      </tr>
      <tr>
        <td>Private keywords</td>
        <td></td>
        <td>✅ Unlimited</td>
      </tr>
      <!-- ... -->
    </table>
    
  2. Pricing cards

    <div class="pricing-cards">
      <div class="card">
        <h3>Monthly</h3>
        <p class="price">$4.99/mo</p>
        <button>Subscribe</button>
      </div>
      <div class="card recommended">
        <span class="badge">Best Value</span>
        <h3>Annual</h3>
        <p class="price">$49/year</p>
        <p class="savings">Save 17%</p>
        <button>Subscribe</button>
      </div>
      <div class="card">
        <h3>Lifetime</h3>
        <p class="price">$99 once</p>
        <button>Buy Now</button>
      </div>
    </div>
    
  3. Stripe checkout integration

    const handleCheckout = async (plan) => {
      const session = await api.post('/stripe/checkout', {
        plan, // 'monthly' | 'annual' | 'lifetime'
        success_url: `${baseUrl}/dashboard?upgraded=true`,
        cancel_url: `${baseUrl}/upgrade`
      });
    
      window.location.href = session.url;
    };
    

6. UX Copy & Messaging

6.1 Upgrade Prompts

Soft (Detail Page):

💡 Want to search in your language? Add personal keywords like 'bekicot' for 🐌
[Upgrade to Personal →]

Strong (Search Miss):

No results for "bekicot"

💎 Create your own keywords with Personal
Add "bekicot → 🐌" and sync it across all devices
[Try Free for 7 Days]

Empty State (Dashboard):

📚 Your Personal Keyword Library

You have 0 keywords.

Upgrade to Personal to:
✓ Add unlimited keywords
✓ Search in your language
✓ Sync across all devices

[Start 7-Day Free Trial]


6.2 Success Messages

After adding keyword:

✓ Added "bekicot" to your library

After editing:

✓ Keyword updated

After deleting:

✓ Keyword removed

After upgrade:

🎉 Welcome to Personal! Start adding your keywords.


6.3 Error Messages

Duplicate keyword:

⚠️ You already have "bekicot" for this emoji

Network error:

Couldn't save. Check your connection and try again.

Unauthorized:

🔒 Please log in to add personal keywords


7. Mobile Considerations

7.1 Detail Page on Mobile

  • Add keyword button: sticky bottom bar (always visible)
  • Modal: full-screen on mobile (easier typing)
  • Keyword list: swipeable cards (swipe left to delete)

7.2 Dashboard on Mobile

  • Tabs: horizontal scroll or bottom nav
  • Table: card view (stack columns vertically)
  • Actions: swipe gestures (edit/delete)

8. Performance & Optimization

8.1 Caching Strategy

Client-side:

  • Cache user keywords in localStorage/sessionStorage
  • Only refetch when:
    • User adds/edits/deletes
    • Page reload after 5 minutes

API-side:

  • ETag support (already implemented)
  • Cache user keywords per user_id (Redis)
  • Invalidate on mutation

8.2 Loading States

Detail page:

Loading user keywords...
└─ Skeleton: [▯▯▯▯] [▯▯▯] [▯▯▯▯▯]

Dashboard:

Loading your library...
└─ Table skeleton (5 rows)

9. Analytics & Tracking

Key Events to Track

Discovery:

  • emoji_viewed (slug, user_tier)
  • public_search (query, has_results)
  • search_miss (query) → upgrade opportunity

Personalization:

  • keyword_added (method: 'quick_add' | 'dashboard')
  • keyword_edited
  • keyword_deleted
  • keywords_exported

Conversion:

  • upgrade_prompt_shown (location: 'detail' | 'search' | 'dashboard')
  • upgrade_clicked (location)
  • trial_started
  • subscription_created (plan: 'monthly' | 'annual' | 'lifetime')

Usage:

  • private_keyword_searched (query, has_results)
  • extension_synced (keyword_count)

10. Testing Checklist

10.1 User State Tests

  • Visitor can search and view emoji details (no login)
  • Visitor sees upgrade CTA (non-intrusive)
  • Free user sees muted keyword section
  • Free user can't add keywords without upgrade
  • Personal user sees active keyword section
  • Personal user can add keywords from detail page
  • Personal user can edit/delete keywords inline

10.2 Flow Tests

  • Quick add: add keyword → appears in list immediately
  • Quick add: new keyword searchable instantly
  • Dashboard: bulk add works correctly
  • Dashboard: export downloads valid JSON
  • Dashboard: import restores keywords
  • Search: private keywords appear first in results
  • Search: private keywords have "Your keyword" badge

10.3 Edge Cases

  • Add duplicate keyword → shows error
  • Delete last keyword for emoji → removes emoji from search
  • Offline: queue mutations, sync when online
  • Rate limit: show friendly error
  • API error: show retry option

11. Implementation Priority

Phase 1: Detail Page Quick Add (Week 1)

  1. Add user keywords section to detail page
  2. Build add keyword modal
  3. Implement POST /keywords/quick endpoint
  4. Add inline edit/delete

Phase 2: Search Blending (Week 1)

  1. Update search to blend private + public
  2. Add "Your keyword" badge to results
  3. Show private matches first

Phase 3: Dashboard (Week 2)

  1. Build My Keywords tab with table
  2. Add bulk actions (import/export)
  3. Implement search/filter

Phase 4: Upgrade Flow (Week 2)

  1. Build upgrade prompts (detail, search miss, dashboard)
  2. Create pricing page
  3. Integrate Stripe checkout

12. Open Questions & Future Enhancements

  1. Keyword suggestions: Should we suggest keywords based on emoji name/category?
  2. Keyboard shortcuts: Quick add keyword with hotkey (Ctrl+K)?
  3. Recently added: Show "Recently added keywords" widget on dashboard?
  4. Keyword collections: Group keywords by category/theme?
  5. Sharing: Allow users to share their keyword libraries with friends?

End of UX Brief

This document defines the seamless user experience for Dewemoji's core value proposition: instant, contextual personalization. Implementation should prioritize the detail page quick-add flow (80% of usage) while building dashboard for power users (20%).