Bounty pages have a per-bounty Open Graph image but no twitter-image, so every Twitter/X share falls back to the generic site card
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 68/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- next.js, react, typescript
Research direction
Read src/app/issues/[id]/opengraph-image.tsx and src/app/issues/[id]/page.tsx:62-66, then check the root image pair and src/app/reputation/[handle]/page.tsx:54-58 to follow their image conventions. Add segment-specific Twitter images for bounty and reputation pages, then extend the social-image test from #665 to verify large-card routes resolve a local image; done when those previews use route-specific images and the test passes.
Written by the indexing model from the issue text.
Description
Location
src/app/issues/[id]/opengraph-image.tsx exists; there is no src/app/issues/[id]/twitter-image.tsx. The declaration that needs one is src/app/issues/[id]/page.tsx:62-66.
Problem
src/app/issues/[id]/ ships a per-bounty Open Graph image route that renders the repo, the bounty title, the reward and the status into a 1200x630 card. But Next.js treats opengraph-image and twitter-image as separate file conventions: opengraph-image emits og:image, and twitter:image comes only from a twitter-image file in the same (or nearest ancestor) segment.
The nearest ancestor twitter-image is the root one, src/app/twitter-image.tsx, which renders renderSocialImage() — the generic "Merge code. / Earn instantly." site card with no bounty-specific content at all.
Meanwhile generateMetadata for the route explicitly declares the large-card format:
twitter: {
card: "summary_large_image",
title,
description,
},
So the page asks for a full-width image card, supplies a bounty-specific title and description, and then hands Twitter a generic image that says nothing about the bounty. The same gap applies to src/app/reputation/[handle]/page.tsx:54-58, which also sets summary_large_image and has no segment-level image route of either kind.
Why it matters
A bounty link shared on Twitter/X is the main organic distribution path for a bounty — it is how a maintainer or sponsor advertises "100 USDC for this issue". On Facebook, LinkedIn and Slack (all OG consumers) the share shows the reward and repo; on Twitter/X it shows the same generic site card as every other MergeFi link, so the one number that makes the link worth clicking is missing. Two shares of two different bounties are visually identical.
Closed issue #696 ("Every bounty page shares the generic OG image — no per-bounty share card") fixed exactly this problem for og:image and left twitter:image on the generic fallback, so the stated goal of #696 is only half met.
Reproduction
npm run build && npm start.curl -s http://localhost:3000/issues/<id> | grep -Ei 'og:image|twitter:image'.og:imagepoints at/issues/<id>/opengraph-image…(the per-bounty card);twitter:imagepoints at the root/twitter-image…(the generic card).- Paste the bounty URL into the Twitter/X card validator, or into any client that honours
twitter:image: the preview shows "Merge code. Earn instantly." with no reward, repo or status.
Suggested fix
Add src/app/issues/[id]/twitter-image.tsx that re-exports the existing generator, mirroring how the root pair already shares social-image.tsx:
export { default, alt, size, contentType } from "./opengraph-image";
(If a re-export of the default proves awkward with the async params signature, make it a thin wrapper that calls the same renderer, and factor the card body out of opengraph-image.tsx into a shared renderBountyCard(params) the way social-image.tsx is shared by the root opengraph-image.tsx and twitter-image.tsx.)
Then do the same for src/app/reputation/[handle]/, which currently has neither an opengraph-image nor a twitter-image despite declaring summary_large_image — a profile share today shows the generic card from both sides.
Extend the social-image test file (added for closed #665) with a check that every segment declaring twitter.card: "summary_large_image" resolves a twitter-image in its own segment, so the next route that sets the large card does not inherit the generic one unnoticed.
- Dominant language
- TypeScript
- Stars
- 1
- Forks
- 94
- Avg merge
- 1h 2m
- Merged PRs (30d)
- 25
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from MergeFi/frontend
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Maintainers usually reply within 1 day
-
bug testing
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Maintainers usually reply within 1 day
-
accessibility bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
MergeFi/frontend#835 · 1 comment ·
Maintainers usually reply within 1 day
All issues in MergeFi/frontend
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
zapcooking/frontend#946 ·
Maintainers usually reply within 1 day
-
enhancement good first issue
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
WiliamRosa/cosmos-semantic-platform#40 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 77/100
liberation-data/drivine#733 · 1 comment ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 64/100
makecindy/cindy#10062 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day