Match ends, Heart of Midlothian 1, St. Johnstone 0.
Hearts moved up to fifth place in the Scottish Premiership as a deflected strike from Kyle Lafferty was enough to edge out St Johnstone at Murrayfield.
The centre forward controlled a shot from Harry Cochrane and his effort on the turn nicked off Joe Shaughnessy to deceive goalkeeper Alan Mannus.
There was little to excite the crowd before the breakthrough on 74 minutes.
Cochrane, just 16, struck the post with the final kick of the ball after a stoppage-time breakaway.
Saints, who drop to sixth, managed just one weak shot on target as they fell to a third consecutive defeat.
The visitors were looking to extend an eight-game unbeaten run against the Edinburgh side but found Hearts in resolute mood at their temporary home.
Lafferty flashed a header wide and Hearts captain Christophe Berra forced a save from Mannus, both chances coming from corners.
Teenager Cochrane was introduced after the interval, with Prince Buaben, who was on a booking, making way.
Jamie Walker has been a hugely influential player for Hearts in recent seasons and the midfielder blasted a volley over the crossbar from the edge of the box and then set up Isma Goncalves, who could only shoot straight into the arms of Mannus.
Saints' solitary glimpse of goal came when David Wotherspoon jinked into the box after good work by O'Halloran but he failed to trouble Jon McLaughlin with a tame strike.
The crowd of 18,534 were becoming impatient before the deadlock was broken.
Callachan's effort from distance was intercepted by Lafferty and the Northern Ireland international had time to spin and fire off a shot.
Defender Shaughnessy's attempted block only took the ball away from Mannus and the ball slipped inside the wrong-footed keeper's post.
It was Lafferty's eighth goal since joining the club from Norwich City in the summer.
With St Johnstone chasing an equaliser in time added on, Hearts came close to a second when the impressive Cochrane crashed an angled shot off the base of the post.
Post-match reaction
Hearts manager Craig Levein: "It was a bit of a war of attrition, but we were the team that managed to see the game out.
"I'm pleased. We don't have a good record against St Johnstone recently.
"Kyle Lafferty gives everything every week and he's still getting up to speed. I think he deserved his goal for his endeavour.
"He got a goal today, but I was even more happy with his attitude."
St Johnstone manager Tommy Wright: "It was a poor game and neither side probably deserved to win.
"Hearts, unfortunately, got the good fortune at the goal.
"In the first half, we got into good positions, but we couldn't cross a road at the moment. I think it's our final ball and it's been like that for a few weeks now.
"The beauty of a midweek game is that we have a chance to bounce back on Tuesday [at home to Ross County]."
Line-ups
Hearts
Formation 4-4-2
- 1McLaughlin
- 30BrandonBooked at 76mins
- 4Souttar
- 6Berra
- 2Smith
- 7Walker
- 20Callachan
- 8BuabenBooked at 7minsSubstituted forCochraneat 45'minutesBooked at 55mins
- 11MilinkovicSubstituted forStocktonat 81'minutes
- 9LaffertyBooked at 61mins
- 77Esmael GonçalvesSubstituted forHendersonat 69'minutes
Substitutes
- 13Hamilton
- 19Nowak
- 23Stockton
- 27Grzelak
- 33Moore
- 43Henderson
- 47Cochrane
St Johnstone
Formation 4-4-2
- 1Mannus
- 14Comrie
- 5Shaughnessy
- 23Gordon
- 24Easton
- 10WotherspoonSubstituted forAlstonat 77'minutes
- 7MillarBooked at 57minsSubstituted forJohnstoneat 81'minutes
- 21ScougallBooked at 24mins
- 26CraigBooked at 90mins
- 9MacLeanSubstituted forCumminsat 67'minutes
- 11O'Halloran
Substitutes
- 3Tanser
- 4Alston
- 12Clark
- 17Johnstone
- 18Paton
- 28Gilchrist
- 29Cummins
- Referee:
- Nick Walsh
- Attendance:
- 18,534
Match Stats
- Possession
- Home58%
- Away42%
- Shots
- Home11
- Away2
- Shots on Target
- Home4
- Away1
- Corners
- Home4
- Away3
- Fouls
- Home16
- Away11
Live Text
Post update
Full Time
Second Half ends, Heart of Midlothian 1, St. Johnstone 0.
Post update
Harry Cochrane (Heart of Midlothian) hits the left post with a right footed shot from the centre of the box.
Post update
Euan Henderson (Heart of Midlothian) wins a free kick in the defensive half.
Post update
Foul by Liam Craig (St. Johnstone).
Post update
Foul by Cole Stockton (Heart of Midlothian).
Post update
Joe Shaughnessy (St. Johnstone) wins a free kick in the attacking half.
Booking
Liam Craig (St. Johnstone) is shown the yellow card for a bad foul.
Post update
Jamie Brandon (Heart of Midlothian) wins a free kick on the left wing.
Post update
Foul by Liam Craig (St. Johnstone).
Post update
Foul by Cole Stockton (Heart of Midlothian).
Post update
Brian Easton (St. Johnstone) wins a free kick in the defensive half.
Post update
Foul by Jamie Walker (Heart of Midlothian).
Post update
Liam Craig (St. Johnstone) wins a free kick in the defensive half.
Substitution
Substitution, Heart of Midlothian. Cole Stockton replaces Manuel Milinkovic.
Substitution
Substitution, St. Johnstone. Denny Johnstone replaces Chris Millar.
Substitution
Substitution, St. Johnstone. Blair Alston replaces David Wotherspoon.
Booking
Jamie Brandon (Heart of Midlothian) is shown the yellow card for a bad foul.
Post update
Stefan Scougall (St. Johnstone) wins a free kick in the defensive half.
Post update
Foul by Jamie Brandon (Heart of Midlothian).