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

Open
#843 0 comments 0 reactions 0 assignees View on GitHub

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
Domain
frontend, web-dev

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

bug

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

  1. npm run build && npm start.
  2. curl -s http://localhost:3000/issues/<id> | grep -Ei 'og:image|twitter:image'.
  3. og:image points at /issues/<id>/opengraph-image… (the per-bounty card); twitter:image points at the root /twitter-image… (the generic card).
  4. 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

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from MergeFi/frontend

All issues in MergeFi/frontend

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.