Jekyll Tweetsert - import Twitter statuses (tweets) as posts
Switch branches/tags
Clone or download
Latest commit a368b69 Jan 28, 2018


Gem Version

Tweetsert is a plugin for Jekyll that pulls recent tweets from one or more Twitter handles, then inserts them (dated appropriately) as regular posts on your site. You can specify which tweets to include or exclude based on patterns or words, import retweets and replies, and tweak the theme and link colors of the embedded tweet.

To organize your tweet-posts, Tweetsert can automatically assign a category and/or tag. You may also choose to automatically import Twitter hashtags.

Why do this?

  1. You want your blog readers to also see your recent tweets when they visit;
  2. You may want to pull in tweets from friends, family, co-workers, etc. into your blog;
  3. You want to create a blog composed only of tweets from a group of people;
  4. Just for fun!

What's new?

v1.1.1 Change cache location, allow inclusion in _config.yml

v1.1.0 Added prefix and suffix options to embed


Add this line to your application's Gemfile:

gem 'jekyll-tweetsert'

And then execute:

$ bundle

Or install it yourself as:

$ gem install jekyll-tweetsert

In compliance with the spirit of Twitter's API usage guidelines, you will need an access token. Get it here:

You will be directed to Twitter's OAuth system. Once you grant permission (read-only), you will be presented with a token that you then place into your _config.yml. If you don't want to do that, you may use the environment variable JTP_ACCESS_TOKEN instead.

$ export JTP_ACCESS_TOKEN="..."
$ jekyll serve


The minimum configuration to run Tweetsert is the following:

  enabled: true
    handle: 'ibrado'
    access_token: "12345678-aBcDeFgHiJkLmNoPqRsTuVwXyZajni01234567890"

Here is a sample _config.yml section, with comments:

  enabled: true
  layout: "tweet" # Template in _layouts to use; default "page"

  # Show additional messages for debugging
  #debug: true

  # Prefix, number of words, and suffix of the generated titles
    #prefix: "[Tweet] "
    words:  9
    suffix: " ..."

  # Some post/page properties you may want to set automatically
  #  is_tweet: true
  #  tweet_html: $    # the embedded tweet
  #  share: false
  #  comments: true

  # The timeline(s) you import, and which tweets you want/don't want
    # Your handle; you may also just use 'handles' below
    handle: 'ibrado'

    # Other handles you want to include
    # If you get an 404 Not Found, you may have misspelled a handle
    #  - 'somehandle'
    #  - 'anotherhandle'

    # The token you got via
    # You may also use the JTP_ACCESS_TOKEN environment variable instead
    access_token: "12345678-aBcDeFgHiJkLmNoPqRsTuVwXyZajni01234567890"

    # Timeline entries to retrieve. Limited by Twitter to 200; default 100
    # Note that this includes deleted tweets, so it's not exact
    limit: 100

    # Include tweets starting with @handle; default: false
    #replies: true

    # Include retweets (RT); default false
    #retweets: true

    # If both include and exclude are configured below,
    # only tweets pulled in by "include" will be further filtered by "exclude"

    # Only include tweets that have these words/handles/hashtags/URLs
    #  (case insensitive regex)
      #- '#blog'
      #- '(^|[^@\w])@(\w{1,15})\b'  # Must mention @someone
      #- 'important'
      #- '@handle'

    # Exclude tweets that have these words/handles/hashtags/URLs
    #   (case insensitive regex)
      - '\d+/'  # Your own blog posts
      - '^.@'                       # Tweets that start with .@someone
      #- 'ignore'
      #- '#somehash'
      #- '@handle'

    # Do not include tweets newer than your latest post; default true
    #no_newer: false

    # Do not include tweets older than your first post; default true
    #no_older: false

    # Set to false if you don't want the excerpt to be set; default true
    #excerpts: false

    # Set to dark if you want a dark background/light text; default: light
    #theme: "dark"

    # Base color of the links, default: set by Twitter
    #link_color: "#80FF80"

    # Include Twitter's oEmbed API script every time; default: false
    # Set to true if you manually include it in e.g. the header
    #omit_script: true

    # Some markup to include right before and after the embedded tweet
    # {{anything}} will be expanded to the corresponding frontmatter/properties
    #prefix: '<i>This was tweeted on {{date}}</i>'
    #suffix: '<i>This is after. Click <a href="{{url}}">here</a> to view this tweet separately.</i>'

    default: "tweets"                  # Automatically set to this category
    dir: ""                            # Folder that contains your categories
    #dir: "categories"                 # Default

    layout: "cat_index"                # What layout to use, inside _layouts
    #layout: "category_index"          # Default

    #  prefix: "Posts in the &laquo;"  # Prefix of the generated title
    #  suffix: "&raquo; category"      # Suffix of the generated title

    #default: "tweet"                  # Tag all tweets automatically with this
    dir: "tag"                         # Location of the generated tag indices
    layout: "tag_index"                #  As above, for tags
    #  prefix: "Posts tagged &ldquo;"
    #  suffix: "&rdquo;"

    hashtags: true                     # Import #hashtags as site tags

    # Hashtags you don't want to import
      - blahblah

    # Automatic tagging based on content, tag: <string or array>
    #  keepkey: "@bitcoinkeepkey"
    #  ethereum: "ethereum"
    #  pets:
    #    - buzzfeedanimals
    #    - Duchess
    #    - Princess
    #    - Athos

Here's another one, cleaned-up:

  enabled: true
  layout: "post"
  debug: false

    prefix: "[Tweet] "
    words:  9
    suffix: " ..."

    is_tweet: true
    tweet_html: $
    share: false
    comments: true

    handle: 'ibrado'

      - 'somehandle'
      - 'anotherhandle'

    access_token: "12345678-aBcDeFgHiJkLmNoPqRsTuVwXyZajni01234567890"
    limit: 100

    replies: false
    retweets: true

    #  - '#blogimport'

      - '\d+/'
      - '^.@'

    no_newer: true
    no_older: false

    excerpts: true
    theme: "dark"
    link_color: "#80FF80"
    omit_script: false
    prefix: '<i>I tweeted this on {{date}}</i>'
    suffix: '<p>Click <a href="{{url}}">here</a> to comment.</p>'

    default: "tweets"
    dir: ""

    layout: "category_index"
      prefix: "Posts in the &laquo;"
      suffix: "&raquo; category"

    default: "tweet"
    dir: "tag"

    layout: "tag_index"
      prefix: "Posts tagged &ldquo;"
      suffix: "&rdquo;"

    hashtags: true
      - "blahblah"

      keepkey: "@bitcoinkeepkey"
      cryptocurrency: [ "bitcoin", "ethereum", "litecoin" ]
        - "ethereum"
        - "@ethereumproject"


Tweetsert caches Twitter's timelines and oEmbed results in a hidden folder in your home, .jekyll-plugins/jekyll-tweetsert. You may delete this if you encounter problems that you think might be related to the cache.

Further configuration

You may want to edit your home/index layout to make the imported tweets look different from the regular ones, for instance,

{% for post in site.posts %}
  {% if post.tags contains "tweet" %}
  {% else %}
    <!-- normal post header -->
  {% endif %}
{% endfor %}

The embedded tweet is wrapped inside a <div class="jekyll-tweetsert">, with embed.prefix inserted before, and embed.suffix after. You may adjust its appearance via CSS:

.jekyll-tweetsert {
  clear: both;
  width: auto;
  margin-left: auto;
  margin-right: auto;
  max-width: max-content;

If you'd rather access the embedded tweet directly, use a property:

    tweet: $

and include it in your layout as {{ page.tweet }} or {{ post.tweet }}. You may want to do this since {{ content }} includes the contents of embed.prefix and embed.suffix and you'd rather exclude them to further tweak the appearance via a custom layout.

This has the nice side-effect of being able to do things like:

{% if page.tweet %}
<p>The following is a tweet:</p>
<div class="my-tweet-class">{{ page.tweet }}</div>
{% else %}
  {{ content }}
{% endif %}


See the author's blog for a demo.


  1. Fork this project:
  2. Clone it (git clone git://
  3. cd jekyll-tweetsert
  4. Create a new branch (e.g. git checkout -b my-bug-fix)
  5. Make your changes
  6. Commit your changes (git commit -m "Bug fix")
  7. Build it (gem build jekyll-tweetsert.gemspec)
  8. Install and test it (gem install ./jekyll-tweetsert-*.gem)
  9. Repeat from step 5 as necessary
  10. Push the branch (git push -u origin my-bug-fix)
  11. Create a Pull Request, making sure to select the proper branch, e.g. my-bug-fix (via*your_user_name*/jekyll-tweetsert)

Bug reports and pull requests are welcome on GitHub at This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.


The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the Jekyll::Tweetsert project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

Also by the author

Jekyll Stickyposts Plugin - Move/pin posts tagged sticky: true before all others. Sorting on custom fields supported, collection and paginator friendly.

Jekyll::Paginate::Content - Split your Jekyll pages, posts, etc. into multiple pages automatically. Single-page view, pager, SEO support, self-adjusting links, multipage-aware Table Of Contents.

Jekyll::ViewSource - Generate pretty or plain HTML and/or Markdown source code pages.